path.js 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372
  1. import { __extends } from "tslib";
  2. import Path from '../graphic/Path.js';
  3. import PathProxy from '../core/PathProxy.js';
  4. import transformPath from './transformPath.js';
  5. import { extend } from '../core/util.js';
  6. var mathSqrt = Math.sqrt;
  7. var mathSin = Math.sin;
  8. var mathCos = Math.cos;
  9. var PI = Math.PI;
  10. function vMag(v) {
  11. return Math.sqrt(v[0] * v[0] + v[1] * v[1]);
  12. }
  13. ;
  14. function vRatio(u, v) {
  15. return (u[0] * v[0] + u[1] * v[1]) / (vMag(u) * vMag(v));
  16. }
  17. ;
  18. function vAngle(u, v) {
  19. return (u[0] * v[1] < u[1] * v[0] ? -1 : 1)
  20. * Math.acos(vRatio(u, v));
  21. }
  22. ;
  23. function processArc(x1, y1, x2, y2, fa, fs, rx, ry, psiDeg, cmd, path) {
  24. var psi = psiDeg * (PI / 180.0);
  25. var xp = mathCos(psi) * (x1 - x2) / 2.0
  26. + mathSin(psi) * (y1 - y2) / 2.0;
  27. var yp = -1 * mathSin(psi) * (x1 - x2) / 2.0
  28. + mathCos(psi) * (y1 - y2) / 2.0;
  29. var lambda = (xp * xp) / (rx * rx) + (yp * yp) / (ry * ry);
  30. if (lambda > 1) {
  31. rx *= mathSqrt(lambda);
  32. ry *= mathSqrt(lambda);
  33. }
  34. var f = (fa === fs ? -1 : 1)
  35. * mathSqrt((((rx * rx) * (ry * ry))
  36. - ((rx * rx) * (yp * yp))
  37. - ((ry * ry) * (xp * xp))) / ((rx * rx) * (yp * yp)
  38. + (ry * ry) * (xp * xp))) || 0;
  39. var cxp = f * rx * yp / ry;
  40. var cyp = f * -ry * xp / rx;
  41. var cx = (x1 + x2) / 2.0
  42. + mathCos(psi) * cxp
  43. - mathSin(psi) * cyp;
  44. var cy = (y1 + y2) / 2.0
  45. + mathSin(psi) * cxp
  46. + mathCos(psi) * cyp;
  47. var theta = vAngle([1, 0], [(xp - cxp) / rx, (yp - cyp) / ry]);
  48. var u = [(xp - cxp) / rx, (yp - cyp) / ry];
  49. var v = [(-1 * xp - cxp) / rx, (-1 * yp - cyp) / ry];
  50. var dTheta = vAngle(u, v);
  51. if (vRatio(u, v) <= -1) {
  52. dTheta = PI;
  53. }
  54. if (vRatio(u, v) >= 1) {
  55. dTheta = 0;
  56. }
  57. if (dTheta < 0) {
  58. var n = Math.round(dTheta / PI * 1e6) / 1e6;
  59. dTheta = PI * 2 + (n % 2) * PI;
  60. }
  61. path.addData(cmd, cx, cy, rx, ry, theta, dTheta, psi, fs);
  62. }
  63. var commandReg = /([mlvhzcqtsa])([^mlvhzcqtsa]*)/ig;
  64. var numberReg = /-?([0-9]*\.)?[0-9]+([eE]-?[0-9]+)?/g;
  65. function createPathProxyFromString(data) {
  66. var path = new PathProxy();
  67. if (!data) {
  68. return path;
  69. }
  70. var cpx = 0;
  71. var cpy = 0;
  72. var subpathX = cpx;
  73. var subpathY = cpy;
  74. var prevCmd;
  75. var CMD = PathProxy.CMD;
  76. var cmdList = data.match(commandReg);
  77. if (!cmdList) {
  78. return path;
  79. }
  80. for (var l = 0; l < cmdList.length; l++) {
  81. var cmdText = cmdList[l];
  82. var cmdStr = cmdText.charAt(0);
  83. var cmd = void 0;
  84. var p = cmdText.match(numberReg) || [];
  85. var pLen = p.length;
  86. for (var i = 0; i < pLen; i++) {
  87. p[i] = parseFloat(p[i]);
  88. }
  89. var off = 0;
  90. while (off < pLen) {
  91. var ctlPtx = void 0;
  92. var ctlPty = void 0;
  93. var rx = void 0;
  94. var ry = void 0;
  95. var psi = void 0;
  96. var fa = void 0;
  97. var fs = void 0;
  98. var x1 = cpx;
  99. var y1 = cpy;
  100. var len = void 0;
  101. var pathData = void 0;
  102. switch (cmdStr) {
  103. case 'l':
  104. cpx += p[off++];
  105. cpy += p[off++];
  106. cmd = CMD.L;
  107. path.addData(cmd, cpx, cpy);
  108. break;
  109. case 'L':
  110. cpx = p[off++];
  111. cpy = p[off++];
  112. cmd = CMD.L;
  113. path.addData(cmd, cpx, cpy);
  114. break;
  115. case 'm':
  116. cpx += p[off++];
  117. cpy += p[off++];
  118. cmd = CMD.M;
  119. path.addData(cmd, cpx, cpy);
  120. subpathX = cpx;
  121. subpathY = cpy;
  122. cmdStr = 'l';
  123. break;
  124. case 'M':
  125. cpx = p[off++];
  126. cpy = p[off++];
  127. cmd = CMD.M;
  128. path.addData(cmd, cpx, cpy);
  129. subpathX = cpx;
  130. subpathY = cpy;
  131. cmdStr = 'L';
  132. break;
  133. case 'h':
  134. cpx += p[off++];
  135. cmd = CMD.L;
  136. path.addData(cmd, cpx, cpy);
  137. break;
  138. case 'H':
  139. cpx = p[off++];
  140. cmd = CMD.L;
  141. path.addData(cmd, cpx, cpy);
  142. break;
  143. case 'v':
  144. cpy += p[off++];
  145. cmd = CMD.L;
  146. path.addData(cmd, cpx, cpy);
  147. break;
  148. case 'V':
  149. cpy = p[off++];
  150. cmd = CMD.L;
  151. path.addData(cmd, cpx, cpy);
  152. break;
  153. case 'C':
  154. cmd = CMD.C;
  155. path.addData(cmd, p[off++], p[off++], p[off++], p[off++], p[off++], p[off++]);
  156. cpx = p[off - 2];
  157. cpy = p[off - 1];
  158. break;
  159. case 'c':
  160. cmd = CMD.C;
  161. path.addData(cmd, p[off++] + cpx, p[off++] + cpy, p[off++] + cpx, p[off++] + cpy, p[off++] + cpx, p[off++] + cpy);
  162. cpx += p[off - 2];
  163. cpy += p[off - 1];
  164. break;
  165. case 'S':
  166. ctlPtx = cpx;
  167. ctlPty = cpy;
  168. len = path.len();
  169. pathData = path.data;
  170. if (prevCmd === CMD.C) {
  171. ctlPtx += cpx - pathData[len - 4];
  172. ctlPty += cpy - pathData[len - 3];
  173. }
  174. cmd = CMD.C;
  175. x1 = p[off++];
  176. y1 = p[off++];
  177. cpx = p[off++];
  178. cpy = p[off++];
  179. path.addData(cmd, ctlPtx, ctlPty, x1, y1, cpx, cpy);
  180. break;
  181. case 's':
  182. ctlPtx = cpx;
  183. ctlPty = cpy;
  184. len = path.len();
  185. pathData = path.data;
  186. if (prevCmd === CMD.C) {
  187. ctlPtx += cpx - pathData[len - 4];
  188. ctlPty += cpy - pathData[len - 3];
  189. }
  190. cmd = CMD.C;
  191. x1 = cpx + p[off++];
  192. y1 = cpy + p[off++];
  193. cpx += p[off++];
  194. cpy += p[off++];
  195. path.addData(cmd, ctlPtx, ctlPty, x1, y1, cpx, cpy);
  196. break;
  197. case 'Q':
  198. x1 = p[off++];
  199. y1 = p[off++];
  200. cpx = p[off++];
  201. cpy = p[off++];
  202. cmd = CMD.Q;
  203. path.addData(cmd, x1, y1, cpx, cpy);
  204. break;
  205. case 'q':
  206. x1 = p[off++] + cpx;
  207. y1 = p[off++] + cpy;
  208. cpx += p[off++];
  209. cpy += p[off++];
  210. cmd = CMD.Q;
  211. path.addData(cmd, x1, y1, cpx, cpy);
  212. break;
  213. case 'T':
  214. ctlPtx = cpx;
  215. ctlPty = cpy;
  216. len = path.len();
  217. pathData = path.data;
  218. if (prevCmd === CMD.Q) {
  219. ctlPtx += cpx - pathData[len - 4];
  220. ctlPty += cpy - pathData[len - 3];
  221. }
  222. cpx = p[off++];
  223. cpy = p[off++];
  224. cmd = CMD.Q;
  225. path.addData(cmd, ctlPtx, ctlPty, cpx, cpy);
  226. break;
  227. case 't':
  228. ctlPtx = cpx;
  229. ctlPty = cpy;
  230. len = path.len();
  231. pathData = path.data;
  232. if (prevCmd === CMD.Q) {
  233. ctlPtx += cpx - pathData[len - 4];
  234. ctlPty += cpy - pathData[len - 3];
  235. }
  236. cpx += p[off++];
  237. cpy += p[off++];
  238. cmd = CMD.Q;
  239. path.addData(cmd, ctlPtx, ctlPty, cpx, cpy);
  240. break;
  241. case 'A':
  242. rx = p[off++];
  243. ry = p[off++];
  244. psi = p[off++];
  245. fa = p[off++];
  246. fs = p[off++];
  247. x1 = cpx, y1 = cpy;
  248. cpx = p[off++];
  249. cpy = p[off++];
  250. cmd = CMD.A;
  251. processArc(x1, y1, cpx, cpy, fa, fs, rx, ry, psi, cmd, path);
  252. break;
  253. case 'a':
  254. rx = p[off++];
  255. ry = p[off++];
  256. psi = p[off++];
  257. fa = p[off++];
  258. fs = p[off++];
  259. x1 = cpx, y1 = cpy;
  260. cpx += p[off++];
  261. cpy += p[off++];
  262. cmd = CMD.A;
  263. processArc(x1, y1, cpx, cpy, fa, fs, rx, ry, psi, cmd, path);
  264. break;
  265. }
  266. }
  267. if (cmdStr === 'z' || cmdStr === 'Z') {
  268. cmd = CMD.Z;
  269. path.addData(cmd);
  270. cpx = subpathX;
  271. cpy = subpathY;
  272. }
  273. prevCmd = cmd;
  274. }
  275. path.toStatic();
  276. return path;
  277. }
  278. var SVGPath = (function (_super) {
  279. __extends(SVGPath, _super);
  280. function SVGPath() {
  281. return _super !== null && _super.apply(this, arguments) || this;
  282. }
  283. SVGPath.prototype.applyTransform = function (m) { };
  284. return SVGPath;
  285. }(Path));
  286. function isPathProxy(path) {
  287. return path.setData != null;
  288. }
  289. function createPathOptions(str, opts) {
  290. var pathProxy = createPathProxyFromString(str);
  291. var innerOpts = extend({}, opts);
  292. innerOpts.buildPath = function (path) {
  293. if (isPathProxy(path)) {
  294. path.setData(pathProxy.data);
  295. var ctx = path.getContext();
  296. if (ctx) {
  297. path.rebuildPath(ctx, 1);
  298. }
  299. }
  300. else {
  301. var ctx = path;
  302. pathProxy.rebuildPath(ctx, 1);
  303. }
  304. };
  305. innerOpts.applyTransform = function (m) {
  306. transformPath(pathProxy, m);
  307. this.dirtyShape();
  308. };
  309. return innerOpts;
  310. }
  311. export function createFromString(str, opts) {
  312. return new SVGPath(createPathOptions(str, opts));
  313. }
  314. export function extendFromString(str, defaultOpts) {
  315. var innerOpts = createPathOptions(str, defaultOpts);
  316. var Sub = (function (_super) {
  317. __extends(Sub, _super);
  318. function Sub(opts) {
  319. var _this = _super.call(this, opts) || this;
  320. _this.applyTransform = innerOpts.applyTransform;
  321. _this.buildPath = innerOpts.buildPath;
  322. return _this;
  323. }
  324. return Sub;
  325. }(SVGPath));
  326. return Sub;
  327. }
  328. export function mergePath(pathEls, opts) {
  329. var pathList = [];
  330. var len = pathEls.length;
  331. for (var i = 0; i < len; i++) {
  332. var pathEl = pathEls[i];
  333. pathList.push(pathEl.getUpdatedPathProxy(true));
  334. }
  335. var pathBundle = new Path(opts);
  336. pathBundle.createPathProxy();
  337. pathBundle.buildPath = function (path) {
  338. if (isPathProxy(path)) {
  339. path.appendPath(pathList);
  340. var ctx = path.getContext();
  341. if (ctx) {
  342. path.rebuildPath(ctx, 1);
  343. }
  344. }
  345. };
  346. return pathBundle;
  347. }
  348. export function clonePath(sourcePath, opts) {
  349. opts = opts || {};
  350. var path = new Path();
  351. if (sourcePath.shape) {
  352. path.setShape(sourcePath.shape);
  353. }
  354. path.setStyle(sourcePath.style);
  355. if (opts.bakeTransform) {
  356. transformPath(path.path, sourcePath.getComputedTransform());
  357. }
  358. else {
  359. if (opts.toLocal) {
  360. path.setLocalTransform(sourcePath.getComputedTransform());
  361. }
  362. else {
  363. path.copyTransform(sourcePath);
  364. }
  365. }
  366. path.buildPath = sourcePath.buildPath;
  367. path.applyTransform = path.applyTransform;
  368. path.z = sourcePath.z;
  369. path.z2 = sourcePath.z2;
  370. path.zlevel = sourcePath.zlevel;
  371. return path;
  372. }