@nasser-sw/fabric 7.0.1-beta3 → 7.0.1-beta4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (105) hide show
  1. package/0 +0 -0
  2. package/dist/index.js +323 -155
  3. package/dist/index.js.map +1 -1
  4. package/dist/index.min.js +1 -1
  5. package/dist/index.min.js.map +1 -1
  6. package/dist/index.min.mjs +1 -1
  7. package/dist/index.min.mjs.map +1 -1
  8. package/dist/index.mjs +323 -155
  9. package/dist/index.mjs.map +1 -1
  10. package/dist/index.node.cjs +323 -155
  11. package/dist/index.node.cjs.map +1 -1
  12. package/dist/index.node.mjs +323 -155
  13. package/dist/index.node.mjs.map +1 -1
  14. package/dist/package.json.min.mjs +1 -1
  15. package/dist/package.json.mjs +1 -1
  16. package/dist/src/shapes/Line.d.ts +31 -86
  17. package/dist/src/shapes/Line.d.ts.map +1 -1
  18. package/dist/src/shapes/Line.min.mjs +1 -1
  19. package/dist/src/shapes/Line.min.mjs.map +1 -1
  20. package/dist/src/shapes/Line.mjs +323 -154
  21. package/dist/src/shapes/Line.mjs.map +1 -1
  22. package/dist-extensions/src/shapes/CustomLine.d.ts +10 -0
  23. package/dist-extensions/src/shapes/CustomLine.d.ts.map +1 -0
  24. package/dist-extensions/src/shapes/Line.d.ts +31 -86
  25. package/dist-extensions/src/shapes/Line.d.ts.map +1 -1
  26. package/fabric-test-editor.html +157 -8
  27. package/fabric-test2.html +513 -0
  28. package/fabric.ts +182 -182
  29. package/package.json +1 -1
  30. package/src/shapes/Line.ts +372 -158
  31. package/debug/konva/CHANGELOG.md +0 -1474
  32. package/debug/konva/LICENSE +0 -22
  33. package/debug/konva/README.md +0 -205
  34. package/debug/konva/gulpfile.mjs +0 -110
  35. package/debug/konva/package.json +0 -139
  36. package/debug/konva/release.sh +0 -65
  37. package/debug/konva/resources/doc-includes/ContainerParams.txt +0 -6
  38. package/debug/konva/resources/doc-includes/NodeParams.txt +0 -20
  39. package/debug/konva/resources/doc-includes/ShapeParams.txt +0 -53
  40. package/debug/konva/resources/jsdoc.conf.json +0 -28
  41. package/debug/konva/rollup.config.mjs +0 -32
  42. package/debug/konva/src/Animation.ts +0 -237
  43. package/debug/konva/src/BezierFunctions.ts +0 -826
  44. package/debug/konva/src/Canvas.ts +0 -193
  45. package/debug/konva/src/Container.ts +0 -649
  46. package/debug/konva/src/Context.ts +0 -1017
  47. package/debug/konva/src/Core.ts +0 -5
  48. package/debug/konva/src/DragAndDrop.ts +0 -173
  49. package/debug/konva/src/Factory.ts +0 -246
  50. package/debug/konva/src/FastLayer.ts +0 -29
  51. package/debug/konva/src/Global.ts +0 -210
  52. package/debug/konva/src/Group.ts +0 -31
  53. package/debug/konva/src/Layer.ts +0 -546
  54. package/debug/konva/src/Node.ts +0 -3477
  55. package/debug/konva/src/PointerEvents.ts +0 -67
  56. package/debug/konva/src/Shape.ts +0 -2081
  57. package/debug/konva/src/Stage.ts +0 -1000
  58. package/debug/konva/src/Tween.ts +0 -811
  59. package/debug/konva/src/Util.ts +0 -1123
  60. package/debug/konva/src/Validators.ts +0 -210
  61. package/debug/konva/src/_CoreInternals.ts +0 -85
  62. package/debug/konva/src/_FullInternals.ts +0 -171
  63. package/debug/konva/src/canvas-backend.ts +0 -36
  64. package/debug/konva/src/filters/Blur.ts +0 -388
  65. package/debug/konva/src/filters/Brighten.ts +0 -48
  66. package/debug/konva/src/filters/Brightness.ts +0 -30
  67. package/debug/konva/src/filters/Contrast.ts +0 -75
  68. package/debug/konva/src/filters/Emboss.ts +0 -207
  69. package/debug/konva/src/filters/Enhance.ts +0 -154
  70. package/debug/konva/src/filters/Grayscale.ts +0 -25
  71. package/debug/konva/src/filters/HSL.ts +0 -108
  72. package/debug/konva/src/filters/HSV.ts +0 -106
  73. package/debug/konva/src/filters/Invert.ts +0 -23
  74. package/debug/konva/src/filters/Kaleidoscope.ts +0 -274
  75. package/debug/konva/src/filters/Mask.ts +0 -220
  76. package/debug/konva/src/filters/Noise.ts +0 -44
  77. package/debug/konva/src/filters/Pixelate.ts +0 -107
  78. package/debug/konva/src/filters/Posterize.ts +0 -46
  79. package/debug/konva/src/filters/RGB.ts +0 -82
  80. package/debug/konva/src/filters/RGBA.ts +0 -103
  81. package/debug/konva/src/filters/Sepia.ts +0 -27
  82. package/debug/konva/src/filters/Solarize.ts +0 -29
  83. package/debug/konva/src/filters/Threshold.ts +0 -44
  84. package/debug/konva/src/index.ts +0 -3
  85. package/debug/konva/src/shapes/Arc.ts +0 -176
  86. package/debug/konva/src/shapes/Arrow.ts +0 -231
  87. package/debug/konva/src/shapes/Circle.ts +0 -76
  88. package/debug/konva/src/shapes/Ellipse.ts +0 -121
  89. package/debug/konva/src/shapes/Image.ts +0 -319
  90. package/debug/konva/src/shapes/Label.ts +0 -386
  91. package/debug/konva/src/shapes/Line.ts +0 -364
  92. package/debug/konva/src/shapes/Path.ts +0 -1013
  93. package/debug/konva/src/shapes/Rect.ts +0 -79
  94. package/debug/konva/src/shapes/RegularPolygon.ts +0 -167
  95. package/debug/konva/src/shapes/Ring.ts +0 -94
  96. package/debug/konva/src/shapes/Sprite.ts +0 -370
  97. package/debug/konva/src/shapes/Star.ts +0 -125
  98. package/debug/konva/src/shapes/Text.ts +0 -1065
  99. package/debug/konva/src/shapes/TextPath.ts +0 -583
  100. package/debug/konva/src/shapes/Transformer.ts +0 -1889
  101. package/debug/konva/src/shapes/Wedge.ts +0 -129
  102. package/debug/konva/src/skia-backend.ts +0 -35
  103. package/debug/konva/src/types.ts +0 -84
  104. package/debug/konva/tsconfig.json +0 -31
  105. package/debug/konva/tsconfig.test.json +0 -7
@@ -1,1013 +0,0 @@
1
- import { Factory } from '../Factory.ts';
2
- import { _registerNode } from '../Global.ts';
3
- import type { ShapeConfig } from '../Shape.ts';
4
- import { Shape } from '../Shape.ts';
5
-
6
- import {
7
- getCubicArcLength,
8
- getQuadraticArcLength,
9
- t2length,
10
- } from '../BezierFunctions.ts';
11
- import type { GetSet, PathSegment } from '../types.ts';
12
-
13
- export interface PathConfig extends ShapeConfig {
14
- data?: string;
15
- }
16
- /**
17
- * Path constructor.
18
- * @author Jason Follas
19
- * @constructor
20
- * @memberof Konva
21
- * @augments Konva.Shape
22
- * @param {Object} config
23
- * @param {String} config.data SVG data string
24
- * @@shapeParams
25
- * @@nodeParams
26
- * @example
27
- * var path = new Konva.Path({
28
- * x: 240,
29
- * y: 40,
30
- * data: 'M12.582,9.551C3.251,16.237,0.921,29.021,7.08,38.564l-2.36,1.689l4.893,2.262l4.893,2.262l-0.568-5.36l-0.567-5.359l-2.365,1.694c-4.657-7.375-2.83-17.185,4.352-22.33c7.451-5.338,17.817-3.625,23.156,3.824c5.337,7.449,3.625,17.813-3.821,23.152l2.857,3.988c9.617-6.893,11.827-20.277,4.935-29.896C35.591,4.87,22.204,2.658,12.582,9.551z',
31
- * fill: 'green',
32
- * scaleX: 2,
33
- * scaleY: 2
34
- * });
35
- */
36
- export class Path extends Shape<PathConfig> {
37
- dataArray: PathSegment[] = [];
38
- pathLength = 0;
39
-
40
- constructor(config?: PathConfig) {
41
- super(config);
42
- this._readDataAttribute();
43
-
44
- this.on('dataChange.konva', function () {
45
- this._readDataAttribute();
46
- });
47
- }
48
-
49
- _readDataAttribute() {
50
- this.dataArray = Path.parsePathData(this.data());
51
- this.pathLength = Path.getPathLength(this.dataArray);
52
- }
53
-
54
- _sceneFunc(context) {
55
- const ca = this.dataArray;
56
-
57
- // context position
58
- context.beginPath();
59
- let isClosed = false;
60
- for (let n = 0; n < ca.length; n++) {
61
- const c = ca[n].command;
62
- const p = ca[n].points;
63
- switch (c) {
64
- case 'L':
65
- context.lineTo(p[0], p[1]);
66
- break;
67
- case 'M':
68
- context.moveTo(p[0], p[1]);
69
- break;
70
- case 'C':
71
- context.bezierCurveTo(p[0], p[1], p[2], p[3], p[4], p[5]);
72
- break;
73
- case 'Q':
74
- context.quadraticCurveTo(p[0], p[1], p[2], p[3]);
75
- break;
76
- case 'A':
77
- const cx = p[0],
78
- cy = p[1],
79
- rx = p[2],
80
- ry = p[3],
81
- theta = p[4],
82
- dTheta = p[5],
83
- psi = p[6],
84
- fs = p[7];
85
-
86
- const r = rx > ry ? rx : ry;
87
- const scaleX = rx > ry ? 1 : rx / ry;
88
- const scaleY = rx > ry ? ry / rx : 1;
89
-
90
- context.translate(cx, cy);
91
- context.rotate(psi);
92
- context.scale(scaleX, scaleY);
93
- context.arc(0, 0, r, theta, theta + dTheta, 1 - fs);
94
- context.scale(1 / scaleX, 1 / scaleY);
95
- context.rotate(-psi);
96
- context.translate(-cx, -cy);
97
-
98
- break;
99
- case 'z':
100
- isClosed = true;
101
- context.closePath();
102
- break;
103
- }
104
- }
105
-
106
- if (!isClosed && !this.hasFill()) {
107
- context.strokeShape(this);
108
- } else {
109
- context.fillStrokeShape(this);
110
- }
111
- }
112
- getSelfRect() {
113
- let points: Array<number> = [];
114
- this.dataArray.forEach(function (data) {
115
- if (data.command === 'A') {
116
- // Approximates by breaking curve into line segments
117
- const start = data.points[4];
118
- // 4 = theta
119
- const dTheta = data.points[5];
120
- // 5 = dTheta
121
- const end = data.points[4] + dTheta;
122
- let inc = Math.PI / 180.0;
123
- // 1 degree resolution
124
- if (Math.abs(start - end) < inc) {
125
- inc = Math.abs(start - end);
126
- }
127
- if (dTheta < 0) {
128
- // clockwise
129
- for (let t = start - inc; t > end; t -= inc) {
130
- const point = Path.getPointOnEllipticalArc(
131
- data.points[0],
132
- data.points[1],
133
- data.points[2],
134
- data.points[3],
135
- t,
136
- 0
137
- );
138
- points.push(point.x, point.y);
139
- }
140
- } else {
141
- // counter-clockwise
142
- for (let t = start + inc; t < end; t += inc) {
143
- const point = Path.getPointOnEllipticalArc(
144
- data.points[0],
145
- data.points[1],
146
- data.points[2],
147
- data.points[3],
148
- t,
149
- 0
150
- );
151
- points.push(point.x, point.y);
152
- }
153
- }
154
- } else if (data.command === 'C') {
155
- // Approximates by breaking curve into 100 line segments
156
- for (let t = 0.0; t <= 1; t += 0.01) {
157
- const point = Path.getPointOnCubicBezier(
158
- t,
159
- data.start.x,
160
- data.start.y,
161
- data.points[0],
162
- data.points[1],
163
- data.points[2],
164
- data.points[3],
165
- data.points[4],
166
- data.points[5]
167
- );
168
- points.push(point.x, point.y);
169
- }
170
- } else {
171
- // TODO: how can we calculate bezier curves better?
172
- points = points.concat(data.points);
173
- }
174
- });
175
- let minX = points[0];
176
- let maxX = points[0];
177
- let minY = points[1];
178
- let maxY = points[1];
179
- let x, y;
180
- for (let i = 0; i < points.length / 2; i++) {
181
- x = points[i * 2];
182
- y = points[i * 2 + 1];
183
-
184
- // skip bad values
185
- if (!isNaN(x)) {
186
- minX = Math.min(minX, x);
187
- maxX = Math.max(maxX, x);
188
- }
189
- if (!isNaN(y)) {
190
- minY = Math.min(minY, y);
191
- maxY = Math.max(maxY, y);
192
- }
193
- }
194
- return {
195
- x: minX,
196
- y: minY,
197
- width: maxX - minX,
198
- height: maxY - minY,
199
- };
200
- }
201
- /**
202
- * Return length of the path.
203
- * @method
204
- * @name Konva.Path#getLength
205
- * @returns {Number} length
206
- * @example
207
- * var length = path.getLength();
208
- */
209
- getLength() {
210
- return this.pathLength;
211
- }
212
- /**
213
- * Get point on path at specific length of the path
214
- * @method
215
- * @name Konva.Path#getPointAtLength
216
- * @param {Number} length length
217
- * @returns {Object} point {x,y} point
218
- * @example
219
- * var point = path.getPointAtLength(10);
220
- */
221
- getPointAtLength(length: number) {
222
- return Path.getPointAtLengthOfDataArray(length, this.dataArray);
223
- }
224
-
225
- data: GetSet<string, this>;
226
-
227
- static getLineLength(x1, y1, x2, y2) {
228
- return Math.sqrt((x2 - x1) * (x2 - x1) + (y2 - y1) * (y2 - y1));
229
- }
230
-
231
- static getPathLength(dataArray: PathSegment[]) {
232
- let pathLength = 0;
233
- for (let i = 0; i < dataArray.length; ++i) {
234
- pathLength += dataArray[i].pathLength;
235
- }
236
- return pathLength;
237
- }
238
-
239
- static getPointAtLengthOfDataArray(length: number, dataArray: PathSegment[]) {
240
- let points: number[],
241
- i = 0,
242
- ii = dataArray.length;
243
-
244
- if (!ii) {
245
- return null;
246
- }
247
-
248
- while (i < ii && length > dataArray[i].pathLength) {
249
- length -= dataArray[i].pathLength;
250
- ++i;
251
- }
252
-
253
- if (i === ii) {
254
- points = dataArray[i - 1].points.slice(-2);
255
- return {
256
- x: points[0],
257
- y: points[1],
258
- };
259
- }
260
-
261
- if (length < 0.01) {
262
- const cmd = dataArray[i].command;
263
- if (cmd === 'M') {
264
- points = dataArray[i].points.slice(0, 2);
265
- return {
266
- x: points[0],
267
- y: points[1],
268
- };
269
- } else {
270
- return {
271
- x: dataArray[i].start.x,
272
- y: dataArray[i].start.y,
273
- };
274
- }
275
- }
276
-
277
- const cp = dataArray[i];
278
- const p = cp.points;
279
- switch (cp.command) {
280
- case 'L':
281
- return Path.getPointOnLine(length, cp.start.x, cp.start.y, p[0], p[1]);
282
- case 'C':
283
- return Path.getPointOnCubicBezier(
284
- t2length(length, Path.getPathLength(dataArray), (i) => {
285
- return getCubicArcLength(
286
- [cp.start.x, p[0], p[2], p[4]],
287
- [cp.start.y, p[1], p[3], p[5]],
288
- i
289
- );
290
- }),
291
- cp.start.x,
292
- cp.start.y,
293
- p[0],
294
- p[1],
295
- p[2],
296
- p[3],
297
- p[4],
298
- p[5]
299
- );
300
- case 'Q':
301
- return Path.getPointOnQuadraticBezier(
302
- t2length(length, Path.getPathLength(dataArray), (i) => {
303
- return getQuadraticArcLength(
304
- [cp.start.x, p[0], p[2]],
305
- [cp.start.y, p[1], p[3]],
306
- i
307
- );
308
- }),
309
- cp.start.x,
310
- cp.start.y,
311
- p[0],
312
- p[1],
313
- p[2],
314
- p[3]
315
- );
316
- case 'A':
317
- const cx = p[0],
318
- cy = p[1],
319
- rx = p[2],
320
- ry = p[3],
321
- dTheta = p[5],
322
- psi = p[6];
323
- let theta = p[4];
324
- theta += (dTheta * length) / cp.pathLength;
325
- return Path.getPointOnEllipticalArc(cx, cy, rx, ry, theta, psi);
326
- }
327
-
328
- return null;
329
- }
330
-
331
- static getPointOnLine(
332
- dist: number,
333
- P1x: number,
334
- P1y: number,
335
- P2x: number,
336
- P2y: number,
337
- fromX?: number,
338
- fromY?: number
339
- ) {
340
- fromX = fromX ?? P1x;
341
- fromY = fromY ?? P1y;
342
-
343
- const len = this.getLineLength(P1x, P1y, P2x, P2y);
344
- if (len < 1e-10) {
345
- return { x: P1x, y: P1y };
346
- }
347
-
348
- if (P2x === P1x) {
349
- // Vertical line
350
- return { x: fromX, y: fromY + (P2y > P1y ? dist : -dist) };
351
- }
352
-
353
- const m = (P2y - P1y) / (P2x - P1x);
354
- const run = Math.sqrt((dist * dist) / (1 + m * m)) * (P2x < P1x ? -1 : 1);
355
- const rise = m * run;
356
-
357
- if (Math.abs(fromY - P1y - m * (fromX - P1x)) < 1e-10) {
358
- return { x: fromX + run, y: fromY + rise };
359
- }
360
-
361
- const u =
362
- ((fromX - P1x) * (P2x - P1x) + (fromY - P1y) * (P2y - P1y)) / (len * len);
363
- const ix = P1x + u * (P2x - P1x);
364
- const iy = P1y + u * (P2y - P1y);
365
- const pRise = this.getLineLength(fromX, fromY, ix, iy);
366
- const pRun = Math.sqrt(dist * dist - pRise * pRise);
367
- const adjustedRun =
368
- Math.sqrt((pRun * pRun) / (1 + m * m)) * (P2x < P1x ? -1 : 1);
369
- const adjustedRise = m * adjustedRun;
370
-
371
- return { x: ix + adjustedRun, y: iy + adjustedRise };
372
- }
373
-
374
- static getPointOnCubicBezier(
375
- pct: number,
376
- P1x: number,
377
- P1y: number,
378
- P2x: number,
379
- P2y: number,
380
- P3x: number,
381
- P3y: number,
382
- P4x: number,
383
- P4y: number
384
- ) {
385
- function CB1(t: number) {
386
- return t * t * t;
387
- }
388
- function CB2(t: number) {
389
- return 3 * t * t * (1 - t);
390
- }
391
- function CB3(t: number) {
392
- return 3 * t * (1 - t) * (1 - t);
393
- }
394
- function CB4(t: number) {
395
- return (1 - t) * (1 - t) * (1 - t);
396
- }
397
- const x = P4x * CB1(pct) + P3x * CB2(pct) + P2x * CB3(pct) + P1x * CB4(pct);
398
- const y = P4y * CB1(pct) + P3y * CB2(pct) + P2y * CB3(pct) + P1y * CB4(pct);
399
-
400
- return { x, y };
401
- }
402
- static getPointOnQuadraticBezier(pct, P1x, P1y, P2x, P2y, P3x, P3y) {
403
- function QB1(t) {
404
- return t * t;
405
- }
406
- function QB2(t) {
407
- return 2 * t * (1 - t);
408
- }
409
- function QB3(t) {
410
- return (1 - t) * (1 - t);
411
- }
412
- const x = P3x * QB1(pct) + P2x * QB2(pct) + P1x * QB3(pct);
413
- const y = P3y * QB1(pct) + P2y * QB2(pct) + P1y * QB3(pct);
414
-
415
- return { x, y };
416
- }
417
- static getPointOnEllipticalArc(
418
- cx: number,
419
- cy: number,
420
- rx: number,
421
- ry: number,
422
- theta: number,
423
- psi: number
424
- ) {
425
- const cosPsi = Math.cos(psi),
426
- sinPsi = Math.sin(psi);
427
- const pt = {
428
- x: rx * Math.cos(theta),
429
- y: ry * Math.sin(theta),
430
- };
431
- return {
432
- x: cx + (pt.x * cosPsi - pt.y * sinPsi),
433
- y: cy + (pt.x * sinPsi + pt.y * cosPsi),
434
- };
435
- }
436
- /*
437
- * get parsed data array from the data
438
- * string. V, v, H, h, and l data are converted to
439
- * L data for the purpose of high performance Path
440
- * rendering
441
- */
442
- static parsePathData(data): PathSegment[] {
443
- // Path Data Segment must begin with a moveTo
444
- //m (x y)+ Relative moveTo (subsequent points are treated as lineTo)
445
- //M (x y)+ Absolute moveTo (subsequent points are treated as lineTo)
446
- //l (x y)+ Relative lineTo
447
- //L (x y)+ Absolute LineTo
448
- //h (x)+ Relative horizontal lineTo
449
- //H (x)+ Absolute horizontal lineTo
450
- //v (y)+ Relative vertical lineTo
451
- //V (y)+ Absolute vertical lineTo
452
- //z (closepath)
453
- //Z (closepath)
454
- //c (x1 y1 x2 y2 x y)+ Relative Bezier curve
455
- //C (x1 y1 x2 y2 x y)+ Absolute Bezier curve
456
- //q (x1 y1 x y)+ Relative Quadratic Bezier
457
- //Q (x1 y1 x y)+ Absolute Quadratic Bezier
458
- //t (x y)+ Shorthand/Smooth Relative Quadratic Bezier
459
- //T (x y)+ Shorthand/Smooth Absolute Quadratic Bezier
460
- //s (x2 y2 x y)+ Shorthand/Smooth Relative Bezier curve
461
- //S (x2 y2 x y)+ Shorthand/Smooth Absolute Bezier curve
462
- //a (rx ry x-axis-rotation large-arc-flag sweep-flag x y)+ Relative Elliptical Arc
463
- //A (rx ry x-axis-rotation large-arc-flag sweep-flag x y)+ Absolute Elliptical Arc
464
-
465
- // return early if data is not defined
466
- if (!data) {
467
- return [];
468
- }
469
-
470
- // command string
471
- let cs = data;
472
-
473
- // command chars
474
- const cc = [
475
- 'm',
476
- 'M',
477
- 'l',
478
- 'L',
479
- 'v',
480
- 'V',
481
- 'h',
482
- 'H',
483
- 'z',
484
- 'Z',
485
- 'c',
486
- 'C',
487
- 'q',
488
- 'Q',
489
- 't',
490
- 'T',
491
- 's',
492
- 'S',
493
- 'a',
494
- 'A',
495
- ];
496
- // convert white spaces to commas
497
- cs = cs.replace(new RegExp(' ', 'g'), ',');
498
- // create pipes so that we can split the data
499
- for (let n = 0; n < cc.length; n++) {
500
- cs = cs.replace(new RegExp(cc[n], 'g'), '|' + cc[n]);
501
- }
502
- // create array
503
- const arr = cs.split('|');
504
- const ca: PathSegment[] = [];
505
- const coords: string[] = [];
506
- // init context point
507
- let cpx = 0;
508
- let cpy = 0;
509
-
510
- const re = /([-+]?((\d+\.\d+)|((\d+)|(\.\d+)))(?:e[-+]?\d+)?)/gi;
511
- let match;
512
- for (let n = 1; n < arr.length; n++) {
513
- let str = arr[n];
514
- let c = str.charAt(0);
515
- str = str.slice(1);
516
-
517
- coords.length = 0;
518
- while ((match = re.exec(str))) {
519
- coords.push(match[0]);
520
- }
521
-
522
- // while ((match = re.exec(str))) {
523
- // coords.push(match[0]);
524
- // }
525
- let p: number[] = [];
526
- // Track param position for A/a commands: 0..6 => rx, ry, psi, fa, fs, x, y
527
- let arcParamIndex = c === 'A' || c === 'a' ? 0 : -1;
528
-
529
- for (let j = 0, jlen = coords.length; j < jlen; j++) {
530
- const token = coords[j];
531
- // extra case for merged flags
532
- if (token === '00') {
533
- p.push(0, 0);
534
- if (arcParamIndex >= 0) {
535
- arcParamIndex += 2;
536
- if (arcParamIndex >= 7) arcParamIndex -= 7;
537
- }
538
- continue;
539
- }
540
- if (arcParamIndex >= 0) {
541
- // index-aware minimal handling for merged flags
542
- if (arcParamIndex === 3) {
543
- // expecting large-arc-flag; token may contain fa+fs(+x)
544
- if (/^[01]{2}\d+(?:\.\d+)?$/.test(token)) {
545
- p.push(parseInt(token[0], 10));
546
- p.push(parseInt(token[1], 10));
547
- p.push(parseFloat(token.slice(2)));
548
- arcParamIndex += 3;
549
- if (arcParamIndex >= 7) arcParamIndex -= 7;
550
- continue;
551
- }
552
- if (token === '11' || token === '10' || token === '01') {
553
- p.push(parseInt(token[0], 10));
554
- p.push(parseInt(token[1], 10));
555
- arcParamIndex += 2;
556
- if (arcParamIndex >= 7) arcParamIndex -= 7;
557
- continue;
558
- }
559
- if (token === '0' || token === '1') {
560
- p.push(parseInt(token, 10));
561
- arcParamIndex += 1;
562
- if (arcParamIndex >= 7) arcParamIndex -= 7;
563
- continue;
564
- }
565
- } else if (arcParamIndex === 4) {
566
- // expecting sweep-flag; token may contain fs(+x)
567
- if (/^[01]\d+(?:\.\d+)?$/.test(token)) {
568
- p.push(parseInt(token[0], 10));
569
- p.push(parseFloat(token.slice(1)));
570
- arcParamIndex += 2;
571
- if (arcParamIndex >= 7) arcParamIndex -= 7;
572
- continue;
573
- }
574
- if (token === '0' || token === '1') {
575
- p.push(parseInt(token, 10));
576
- arcParamIndex += 1;
577
- if (arcParamIndex >= 7) arcParamIndex -= 7;
578
- continue;
579
- }
580
- }
581
- const parsedArc = parseFloat(token);
582
- if (!isNaN(parsedArc)) {
583
- p.push(parsedArc);
584
- } else {
585
- p.push(0);
586
- }
587
- arcParamIndex += 1;
588
- if (arcParamIndex >= 7) arcParamIndex -= 7;
589
- } else {
590
- const parsed = parseFloat(token);
591
- if (!isNaN(parsed)) {
592
- p.push(parsed);
593
- } else {
594
- p.push(0);
595
- }
596
- }
597
- }
598
-
599
- while (p.length > 0) {
600
- if (isNaN(p[0])) {
601
- // case for a trailing comma before next command
602
- break;
603
- }
604
-
605
- let cmd: string = '';
606
- let points: number[] = [];
607
- const startX = cpx,
608
- startY = cpy;
609
- // Move var from within the switch to up here (jshint)
610
- let prevCmd, ctlPtx, ctlPty; // Ss, Tt
611
- let rx, ry, psi, fa, fs, x1, y1; // Aa
612
-
613
- // convert l, H, h, V, and v to L
614
- switch (c) {
615
- // Note: Keep the lineTo's above the moveTo's in this switch
616
- case 'l':
617
- cpx += p.shift()!;
618
- cpy += p.shift()!;
619
- cmd = 'L';
620
- points.push(cpx, cpy);
621
- break;
622
- case 'L':
623
- cpx = p.shift()!;
624
- cpy = p.shift()!;
625
- points.push(cpx, cpy);
626
- break;
627
- // Note: lineTo handlers need to be above this point
628
- case 'm':
629
- const dx = p.shift()!;
630
- const dy = p.shift()!;
631
- cpx += dx;
632
- cpy += dy;
633
- cmd = 'M';
634
- // After closing the path move the current position
635
- // to the the first point of the path (if any).
636
- if (ca.length > 2 && ca[ca.length - 1].command === 'z') {
637
- for (let idx = ca.length - 2; idx >= 0; idx--) {
638
- if (ca[idx].command === 'M') {
639
- cpx = ca[idx].points[0] + dx;
640
- cpy = ca[idx].points[1] + dy;
641
- break;
642
- }
643
- }
644
- }
645
- points.push(cpx, cpy);
646
- c = 'l';
647
- // subsequent points are treated as relative lineTo
648
- break;
649
- case 'M':
650
- cpx = p.shift()!;
651
- cpy = p.shift()!;
652
- cmd = 'M';
653
- points.push(cpx, cpy);
654
- c = 'L';
655
- // subsequent points are treated as absolute lineTo
656
- break;
657
-
658
- case 'h':
659
- cpx += p.shift()!;
660
- cmd = 'L';
661
- points.push(cpx, cpy);
662
- break;
663
- case 'H':
664
- cpx = p.shift()!;
665
- cmd = 'L';
666
- points.push(cpx, cpy);
667
- break;
668
- case 'v':
669
- cpy += p.shift()!;
670
- cmd = 'L';
671
- points.push(cpx, cpy);
672
- break;
673
- case 'V':
674
- cpy = p.shift()!;
675
- cmd = 'L';
676
- points.push(cpx, cpy);
677
- break;
678
- case 'C':
679
- points.push(p.shift()!, p.shift()!, p.shift()!, p.shift()!);
680
- cpx = p.shift()!;
681
- cpy = p.shift()!;
682
- points.push(cpx, cpy);
683
- break;
684
- case 'c':
685
- points.push(
686
- cpx + p.shift()!,
687
- cpy + p.shift()!,
688
- cpx + p.shift()!,
689
- cpy + p.shift()!
690
- );
691
- cpx += p.shift()!;
692
- cpy += p.shift()!;
693
- cmd = 'C';
694
- points.push(cpx, cpy);
695
- break;
696
- case 'S':
697
- ctlPtx = cpx;
698
- ctlPty = cpy;
699
- prevCmd = ca[ca.length - 1];
700
- if (prevCmd.command === 'C') {
701
- ctlPtx = cpx + (cpx - prevCmd.points[2]);
702
- ctlPty = cpy + (cpy - prevCmd.points[3]);
703
- }
704
- points.push(ctlPtx, ctlPty, p.shift()!, p.shift()!);
705
- cpx = p.shift()!;
706
- cpy = p.shift()!;
707
- cmd = 'C';
708
- points.push(cpx, cpy);
709
- break;
710
- case 's':
711
- ctlPtx = cpx;
712
- ctlPty = cpy;
713
- prevCmd = ca[ca.length - 1];
714
- if (prevCmd.command === 'C') {
715
- ctlPtx = cpx + (cpx - prevCmd.points[2]);
716
- ctlPty = cpy + (cpy - prevCmd.points[3]);
717
- }
718
- points.push(ctlPtx, ctlPty, cpx + p.shift()!, cpy + p.shift()!);
719
- cpx += p.shift()!;
720
- cpy += p.shift()!;
721
- cmd = 'C';
722
- points.push(cpx, cpy);
723
- break;
724
- case 'Q':
725
- points.push(p.shift()!, p.shift()!);
726
- cpx = p.shift()!;
727
- cpy = p.shift()!;
728
- points.push(cpx, cpy);
729
- break;
730
- case 'q':
731
- points.push(cpx + p.shift()!, cpy + p.shift()!);
732
- cpx += p.shift()!;
733
- cpy += p.shift()!;
734
- cmd = 'Q';
735
- points.push(cpx, cpy);
736
- break;
737
- case 'T':
738
- ctlPtx = cpx;
739
- ctlPty = cpy;
740
- prevCmd = ca[ca.length - 1];
741
- if (prevCmd.command === 'Q') {
742
- ctlPtx = cpx + (cpx - prevCmd.points[0]);
743
- ctlPty = cpy + (cpy - prevCmd.points[1]);
744
- }
745
- cpx = p.shift()!;
746
- cpy = p.shift()!;
747
- cmd = 'Q';
748
- points.push(ctlPtx, ctlPty, cpx, cpy);
749
- break;
750
- case 't':
751
- ctlPtx = cpx;
752
- ctlPty = cpy;
753
- prevCmd = ca[ca.length - 1];
754
- if (prevCmd.command === 'Q') {
755
- ctlPtx = cpx + (cpx - prevCmd.points[0]);
756
- ctlPty = cpy + (cpy - prevCmd.points[1]);
757
- }
758
- cpx += p.shift()!;
759
- cpy += p.shift()!;
760
- cmd = 'Q';
761
- points.push(ctlPtx, ctlPty, cpx, cpy);
762
- break;
763
- case 'A':
764
- rx = p.shift()!;
765
- ry = p.shift()!;
766
- psi = p.shift()!;
767
- fa = p.shift()!;
768
- fs = p.shift()!;
769
- x1 = cpx;
770
- y1 = cpy;
771
- cpx = p.shift()!;
772
- cpy = p.shift()!;
773
- cmd = 'A';
774
- points = this.convertEndpointToCenterParameterization(
775
- x1,
776
- y1,
777
- cpx,
778
- cpy,
779
- fa,
780
- fs,
781
- rx,
782
- ry,
783
- psi
784
- );
785
- break;
786
- case 'a':
787
- rx = p.shift();
788
- ry = p.shift();
789
- psi = p.shift();
790
- fa = p.shift();
791
- fs = p.shift();
792
- x1 = cpx;
793
- y1 = cpy;
794
- cpx += p.shift()!;
795
- cpy += p.shift()!;
796
- cmd = 'A';
797
- points = this.convertEndpointToCenterParameterization(
798
- x1,
799
- y1,
800
- cpx,
801
- cpy,
802
- fa,
803
- fs,
804
- rx,
805
- ry,
806
- psi
807
- );
808
- break;
809
- }
810
-
811
- ca.push({
812
- command: cmd || c,
813
- points: points,
814
- start: {
815
- x: startX,
816
- y: startY,
817
- },
818
- pathLength: this.calcLength(startX, startY, cmd || c, points),
819
- });
820
- }
821
-
822
- if (c === 'z' || c === 'Z') {
823
- ca.push({
824
- command: 'z',
825
- points: [],
826
- start: undefined as any,
827
- pathLength: 0,
828
- });
829
- }
830
- }
831
-
832
- return ca;
833
- }
834
- static calcLength(x, y, cmd, points) {
835
- let len, p1, p2, t;
836
- const path = Path;
837
-
838
- switch (cmd) {
839
- case 'L':
840
- return path.getLineLength(x, y, points[0], points[1]);
841
- case 'C':
842
- return getCubicArcLength(
843
- [x, points[0], points[2], points[4]],
844
- [y, points[1], points[3], points[5]],
845
- 1
846
- );
847
- case 'Q':
848
- return getQuadraticArcLength(
849
- [x, points[0], points[2]],
850
- [y, points[1], points[3]],
851
- 1
852
- );
853
- case 'A':
854
- // Approximates by breaking curve into line segments
855
- len = 0.0;
856
- const start = points[4];
857
- // 4 = theta
858
- const dTheta = points[5];
859
- // 5 = dTheta
860
- const end = points[4] + dTheta;
861
- let inc = Math.PI / 180.0;
862
- // 1 degree resolution
863
- if (Math.abs(start - end) < inc) {
864
- inc = Math.abs(start - end);
865
- }
866
- // Note: for purpose of calculating arc length, not going to worry about rotating X-axis by angle psi
867
- p1 = path.getPointOnEllipticalArc(
868
- points[0],
869
- points[1],
870
- points[2],
871
- points[3],
872
- start,
873
- 0
874
- );
875
- if (dTheta < 0) {
876
- // clockwise
877
- for (t = start - inc; t > end; t -= inc) {
878
- p2 = path.getPointOnEllipticalArc(
879
- points[0],
880
- points[1],
881
- points[2],
882
- points[3],
883
- t,
884
- 0
885
- );
886
- len += path.getLineLength(p1.x, p1.y, p2.x, p2.y);
887
- p1 = p2;
888
- }
889
- } else {
890
- // counter-clockwise
891
- for (t = start + inc; t < end; t += inc) {
892
- p2 = path.getPointOnEllipticalArc(
893
- points[0],
894
- points[1],
895
- points[2],
896
- points[3],
897
- t,
898
- 0
899
- );
900
- len += path.getLineLength(p1.x, p1.y, p2.x, p2.y);
901
- p1 = p2;
902
- }
903
- }
904
- p2 = path.getPointOnEllipticalArc(
905
- points[0],
906
- points[1],
907
- points[2],
908
- points[3],
909
- end,
910
- 0
911
- );
912
- len += path.getLineLength(p1.x, p1.y, p2.x, p2.y);
913
-
914
- return len;
915
- }
916
-
917
- return 0;
918
- }
919
- static convertEndpointToCenterParameterization(
920
- x1: number,
921
- y1: number,
922
- x2: number,
923
- y2: number,
924
- fa: number,
925
- fs: number,
926
- rx: number,
927
- ry: number,
928
- psiDeg: number
929
- ) {
930
- // Derived from: http://www.w3.org/TR/SVG/implnote.html#ArcImplementationNotes
931
- const psi = psiDeg * (Math.PI / 180.0);
932
- const xp =
933
- (Math.cos(psi) * (x1 - x2)) / 2.0 + (Math.sin(psi) * (y1 - y2)) / 2.0;
934
- const yp =
935
- (-1 * Math.sin(psi) * (x1 - x2)) / 2.0 +
936
- (Math.cos(psi) * (y1 - y2)) / 2.0;
937
-
938
- const lambda = (xp * xp) / (rx * rx) + (yp * yp) / (ry * ry);
939
-
940
- if (lambda > 1) {
941
- rx *= Math.sqrt(lambda);
942
- ry *= Math.sqrt(lambda);
943
- }
944
-
945
- let f = Math.sqrt(
946
- (rx * rx * (ry * ry) - rx * rx * (yp * yp) - ry * ry * (xp * xp)) /
947
- (rx * rx * (yp * yp) + ry * ry * (xp * xp))
948
- );
949
-
950
- if (fa === fs) {
951
- f *= -1;
952
- }
953
- if (isNaN(f)) {
954
- f = 0;
955
- }
956
-
957
- const cxp = (f * rx * yp) / ry;
958
- const cyp = (f * -ry * xp) / rx;
959
-
960
- const cx = (x1 + x2) / 2.0 + Math.cos(psi) * cxp - Math.sin(psi) * cyp;
961
- const cy = (y1 + y2) / 2.0 + Math.sin(psi) * cxp + Math.cos(psi) * cyp;
962
-
963
- const vMag = function (v) {
964
- return Math.sqrt(v[0] * v[0] + v[1] * v[1]);
965
- };
966
- const vRatio = function (u, v) {
967
- return (u[0] * v[0] + u[1] * v[1]) / (vMag(u) * vMag(v));
968
- };
969
- const vAngle = function (u, v) {
970
- return (u[0] * v[1] < u[1] * v[0] ? -1 : 1) * Math.acos(vRatio(u, v));
971
- };
972
- const theta = vAngle([1, 0], [(xp - cxp) / rx, (yp - cyp) / ry]);
973
- const u = [(xp - cxp) / rx, (yp - cyp) / ry];
974
- const v = [(-1 * xp - cxp) / rx, (-1 * yp - cyp) / ry];
975
- let dTheta = vAngle(u, v);
976
-
977
- if (vRatio(u, v) <= -1) {
978
- dTheta = Math.PI;
979
- }
980
- if (vRatio(u, v) >= 1) {
981
- dTheta = 0;
982
- }
983
- if (fs === 0 && dTheta > 0) {
984
- dTheta = dTheta - 2 * Math.PI;
985
- }
986
- if (fs === 1 && dTheta < 0) {
987
- dTheta = dTheta + 2 * Math.PI;
988
- }
989
- return [cx, cy, rx, ry, theta, dTheta, psi, fs];
990
- }
991
- }
992
-
993
- Path.prototype.className = 'Path';
994
- Path.prototype._attrsAffectingSize = ['data'];
995
- _registerNode(Path);
996
-
997
- /**
998
- * get/set SVG path data string. This method
999
- * also automatically parses the data string
1000
- * into a data array. Currently supported SVG data:
1001
- * M, m, L, l, H, h, V, v, Q, q, T, t, C, c, S, s, A, a, Z, z
1002
- * @name Konva.Path#data
1003
- * @method
1004
- * @param {String} data svg path string
1005
- * @returns {String}
1006
- * @example
1007
- * // get data
1008
- * var data = path.data();
1009
- *
1010
- * // set data
1011
- * path.data('M200,100h100v50z');
1012
- */
1013
- Factory.addGetterSetter(Path, 'data');