@nasser-sw/fabric 7.0.1-beta1 → 7.0.1-beta10

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 (181) hide show
  1. package/0 +0 -0
  2. package/debug/{konva → konva-master}/CHANGELOG.md +2 -1
  3. package/debug/{konva → konva-master}/README.md +7 -3
  4. package/debug/{konva → konva-master}/package.json +1 -1
  5. package/debug/{konva → konva-master}/release.sh +1 -4
  6. package/debug/{konva → konva-master}/src/Canvas.ts +37 -0
  7. package/debug/{konva → konva-master}/src/shapes/Text.ts +2 -2
  8. package/dist/index.js +1853 -288
  9. package/dist/index.js.map +1 -1
  10. package/dist/index.min.js +1 -1
  11. package/dist/index.min.js.map +1 -1
  12. package/dist/index.min.mjs +1 -1
  13. package/dist/index.min.mjs.map +1 -1
  14. package/dist/index.mjs +1853 -288
  15. package/dist/index.mjs.map +1 -1
  16. package/dist/index.node.cjs +1853 -288
  17. package/dist/index.node.cjs.map +1 -1
  18. package/dist/index.node.mjs +1853 -288
  19. package/dist/index.node.mjs.map +1 -1
  20. package/dist/package.json.min.mjs +1 -1
  21. package/dist/package.json.mjs +1 -1
  22. package/dist/src/shapes/Line.d.ts +33 -86
  23. package/dist/src/shapes/Line.d.ts.map +1 -1
  24. package/dist/src/shapes/Line.min.mjs +1 -1
  25. package/dist/src/shapes/Line.min.mjs.map +1 -1
  26. package/dist/src/shapes/Line.mjs +405 -159
  27. package/dist/src/shapes/Line.mjs.map +1 -1
  28. package/dist/src/shapes/Polyline.d.ts +7 -0
  29. package/dist/src/shapes/Polyline.d.ts.map +1 -1
  30. package/dist/src/shapes/Polyline.min.mjs +1 -1
  31. package/dist/src/shapes/Polyline.min.mjs.map +1 -1
  32. package/dist/src/shapes/Polyline.mjs +48 -16
  33. package/dist/src/shapes/Polyline.mjs.map +1 -1
  34. package/dist/src/shapes/Text/Text.d.ts +19 -0
  35. package/dist/src/shapes/Text/Text.d.ts.map +1 -1
  36. package/dist/src/shapes/Text/Text.min.mjs +1 -1
  37. package/dist/src/shapes/Text/Text.min.mjs.map +1 -1
  38. package/dist/src/shapes/Text/Text.mjs +302 -16
  39. package/dist/src/shapes/Text/Text.mjs.map +1 -1
  40. package/dist/src/shapes/Textbox.d.ts +43 -1
  41. package/dist/src/shapes/Textbox.d.ts.map +1 -1
  42. package/dist/src/shapes/Textbox.min.mjs +1 -1
  43. package/dist/src/shapes/Textbox.min.mjs.map +1 -1
  44. package/dist/src/shapes/Textbox.mjs +521 -67
  45. package/dist/src/shapes/Textbox.mjs.map +1 -1
  46. package/dist/src/shapes/Triangle.d.ts +27 -2
  47. package/dist/src/shapes/Triangle.d.ts.map +1 -1
  48. package/dist/src/shapes/Triangle.min.mjs +1 -1
  49. package/dist/src/shapes/Triangle.min.mjs.map +1 -1
  50. package/dist/src/shapes/Triangle.mjs +72 -12
  51. package/dist/src/shapes/Triangle.mjs.map +1 -1
  52. package/dist/src/text/examples/arabicTextExample.d.ts +60 -0
  53. package/dist/src/text/examples/arabicTextExample.d.ts.map +1 -0
  54. package/dist/src/text/measure.d.ts +9 -0
  55. package/dist/src/text/measure.d.ts.map +1 -1
  56. package/dist/src/text/measure.min.mjs +1 -1
  57. package/dist/src/text/measure.min.mjs.map +1 -1
  58. package/dist/src/text/measure.mjs +175 -4
  59. package/dist/src/text/measure.mjs.map +1 -1
  60. package/dist/src/text/overlayEditor.d.ts.map +1 -1
  61. package/dist/src/text/overlayEditor.min.mjs +1 -1
  62. package/dist/src/text/overlayEditor.min.mjs.map +1 -1
  63. package/dist/src/text/overlayEditor.mjs +155 -9
  64. package/dist/src/text/overlayEditor.mjs.map +1 -1
  65. package/dist/src/text/scriptUtils.d.ts +142 -0
  66. package/dist/src/text/scriptUtils.d.ts.map +1 -0
  67. package/dist/src/text/scriptUtils.min.mjs +2 -0
  68. package/dist/src/text/scriptUtils.min.mjs.map +1 -0
  69. package/dist/src/text/scriptUtils.mjs +212 -0
  70. package/dist/src/text/scriptUtils.mjs.map +1 -0
  71. package/dist/src/util/misc/cornerRadius.d.ts +70 -0
  72. package/dist/src/util/misc/cornerRadius.d.ts.map +1 -0
  73. package/dist/src/util/misc/cornerRadius.min.mjs +2 -0
  74. package/dist/src/util/misc/cornerRadius.min.mjs.map +1 -0
  75. package/dist/src/util/misc/cornerRadius.mjs +181 -0
  76. package/dist/src/util/misc/cornerRadius.mjs.map +1 -0
  77. package/dist-extensions/src/shapes/CustomLine.d.ts +10 -0
  78. package/dist-extensions/src/shapes/CustomLine.d.ts.map +1 -0
  79. package/dist-extensions/src/shapes/Line.d.ts +33 -86
  80. package/dist-extensions/src/shapes/Line.d.ts.map +1 -1
  81. package/dist-extensions/src/shapes/Polyline.d.ts +7 -0
  82. package/dist-extensions/src/shapes/Polyline.d.ts.map +1 -1
  83. package/dist-extensions/src/shapes/Text/Text.d.ts +19 -0
  84. package/dist-extensions/src/shapes/Text/Text.d.ts.map +1 -1
  85. package/dist-extensions/src/shapes/Textbox.d.ts +43 -1
  86. package/dist-extensions/src/shapes/Textbox.d.ts.map +1 -1
  87. package/dist-extensions/src/shapes/Triangle.d.ts +27 -2
  88. package/dist-extensions/src/shapes/Triangle.d.ts.map +1 -1
  89. package/dist-extensions/src/text/measure.d.ts +9 -0
  90. package/dist-extensions/src/text/measure.d.ts.map +1 -1
  91. package/dist-extensions/src/text/overlayEditor.d.ts.map +1 -1
  92. package/dist-extensions/src/text/scriptUtils.d.ts +142 -0
  93. package/dist-extensions/src/text/scriptUtils.d.ts.map +1 -0
  94. package/dist-extensions/src/util/misc/cornerRadius.d.ts +70 -0
  95. package/dist-extensions/src/util/misc/cornerRadius.d.ts.map +1 -0
  96. package/fabric-test-editor.html +3552 -0
  97. package/fabric-test2.html +647 -0
  98. package/fabric.ts +182 -182
  99. package/fonts/STV Bold.ttf +0 -0
  100. package/fonts/STV Light.ttf +0 -0
  101. package/fonts/STV Regular.ttf +0 -0
  102. package/package.json +164 -164
  103. package/src/shapes/Line.ts +484 -157
  104. package/src/shapes/Polyline.ts +70 -29
  105. package/src/shapes/Text/Text.ts +317 -19
  106. package/src/shapes/Textbox.ts +544 -12
  107. package/src/shapes/Triangle.spec.ts +76 -0
  108. package/src/shapes/Triangle.ts +85 -15
  109. package/src/text/measure.ts +200 -50
  110. package/src/text/overlayEditor.ts +164 -12
  111. package/src/util/misc/cornerRadius.spec.ts +141 -0
  112. package/src/util/misc/cornerRadius.ts +269 -0
  113. /package/debug/{konva → konva-master}/LICENSE +0 -0
  114. /package/debug/{konva → konva-master}/gulpfile.mjs +0 -0
  115. /package/debug/{konva → konva-master}/resources/doc-includes/ContainerParams.txt +0 -0
  116. /package/debug/{konva → konva-master}/resources/doc-includes/NodeParams.txt +0 -0
  117. /package/debug/{konva → konva-master}/resources/doc-includes/ShapeParams.txt +0 -0
  118. /package/debug/{konva → konva-master}/resources/jsdoc.conf.json +0 -0
  119. /package/debug/{konva → konva-master}/rollup.config.mjs +0 -0
  120. /package/debug/{konva → konva-master}/src/Animation.ts +0 -0
  121. /package/debug/{konva → konva-master}/src/BezierFunctions.ts +0 -0
  122. /package/debug/{konva → konva-master}/src/Container.ts +0 -0
  123. /package/debug/{konva → konva-master}/src/Context.ts +0 -0
  124. /package/debug/{konva → konva-master}/src/Core.ts +0 -0
  125. /package/debug/{konva → konva-master}/src/DragAndDrop.ts +0 -0
  126. /package/debug/{konva → konva-master}/src/Factory.ts +0 -0
  127. /package/debug/{konva → konva-master}/src/FastLayer.ts +0 -0
  128. /package/debug/{konva → konva-master}/src/Global.ts +0 -0
  129. /package/debug/{konva → konva-master}/src/Group.ts +0 -0
  130. /package/debug/{konva → konva-master}/src/Layer.ts +0 -0
  131. /package/debug/{konva → konva-master}/src/Node.ts +0 -0
  132. /package/debug/{konva → konva-master}/src/PointerEvents.ts +0 -0
  133. /package/debug/{konva → konva-master}/src/Shape.ts +0 -0
  134. /package/debug/{konva → konva-master}/src/Stage.ts +0 -0
  135. /package/debug/{konva → konva-master}/src/Tween.ts +0 -0
  136. /package/debug/{konva → konva-master}/src/Util.ts +0 -0
  137. /package/debug/{konva → konva-master}/src/Validators.ts +0 -0
  138. /package/debug/{konva → konva-master}/src/_CoreInternals.ts +0 -0
  139. /package/debug/{konva → konva-master}/src/_FullInternals.ts +0 -0
  140. /package/debug/{konva → konva-master}/src/canvas-backend.ts +0 -0
  141. /package/debug/{konva → konva-master}/src/filters/Blur.ts +0 -0
  142. /package/debug/{konva → konva-master}/src/filters/Brighten.ts +0 -0
  143. /package/debug/{konva → konva-master}/src/filters/Brightness.ts +0 -0
  144. /package/debug/{konva → konva-master}/src/filters/Contrast.ts +0 -0
  145. /package/debug/{konva → konva-master}/src/filters/Emboss.ts +0 -0
  146. /package/debug/{konva → konva-master}/src/filters/Enhance.ts +0 -0
  147. /package/debug/{konva → konva-master}/src/filters/Grayscale.ts +0 -0
  148. /package/debug/{konva → konva-master}/src/filters/HSL.ts +0 -0
  149. /package/debug/{konva → konva-master}/src/filters/HSV.ts +0 -0
  150. /package/debug/{konva → konva-master}/src/filters/Invert.ts +0 -0
  151. /package/debug/{konva → konva-master}/src/filters/Kaleidoscope.ts +0 -0
  152. /package/debug/{konva → konva-master}/src/filters/Mask.ts +0 -0
  153. /package/debug/{konva → konva-master}/src/filters/Noise.ts +0 -0
  154. /package/debug/{konva → konva-master}/src/filters/Pixelate.ts +0 -0
  155. /package/debug/{konva → konva-master}/src/filters/Posterize.ts +0 -0
  156. /package/debug/{konva → konva-master}/src/filters/RGB.ts +0 -0
  157. /package/debug/{konva → konva-master}/src/filters/RGBA.ts +0 -0
  158. /package/debug/{konva → konva-master}/src/filters/Sepia.ts +0 -0
  159. /package/debug/{konva → konva-master}/src/filters/Solarize.ts +0 -0
  160. /package/debug/{konva → konva-master}/src/filters/Threshold.ts +0 -0
  161. /package/debug/{konva → konva-master}/src/index.ts +0 -0
  162. /package/debug/{konva → konva-master}/src/shapes/Arc.ts +0 -0
  163. /package/debug/{konva → konva-master}/src/shapes/Arrow.ts +0 -0
  164. /package/debug/{konva → konva-master}/src/shapes/Circle.ts +0 -0
  165. /package/debug/{konva → konva-master}/src/shapes/Ellipse.ts +0 -0
  166. /package/debug/{konva → konva-master}/src/shapes/Image.ts +0 -0
  167. /package/debug/{konva → konva-master}/src/shapes/Label.ts +0 -0
  168. /package/debug/{konva → konva-master}/src/shapes/Line.ts +0 -0
  169. /package/debug/{konva → konva-master}/src/shapes/Path.ts +0 -0
  170. /package/debug/{konva → konva-master}/src/shapes/Rect.ts +0 -0
  171. /package/debug/{konva → konva-master}/src/shapes/RegularPolygon.ts +0 -0
  172. /package/debug/{konva → konva-master}/src/shapes/Ring.ts +0 -0
  173. /package/debug/{konva → konva-master}/src/shapes/Sprite.ts +0 -0
  174. /package/debug/{konva → konva-master}/src/shapes/Star.ts +0 -0
  175. /package/debug/{konva → konva-master}/src/shapes/TextPath.ts +0 -0
  176. /package/debug/{konva → konva-master}/src/shapes/Transformer.ts +0 -0
  177. /package/debug/{konva → konva-master}/src/shapes/Wedge.ts +0 -0
  178. /package/debug/{konva → konva-master}/src/skia-backend.ts +0 -0
  179. /package/debug/{konva → konva-master}/src/types.ts +0 -0
  180. /package/debug/{konva → konva-master}/tsconfig.json +0 -0
  181. /package/debug/{konva → konva-master}/tsconfig.test.json +0 -0
@@ -14,35 +14,34 @@ import { makeBoundingBoxFromPoints } from '../util/misc/boundingBoxFromPoints.mj
14
14
  import '../cache.mjs';
15
15
  import '../parser/constants.mjs';
16
16
  import '../util/animation/AnimationRegistry.mjs';
17
+ import { Control } from '../controls/Control.mjs';
18
+ import { Gradient } from '../gradient/Gradient.mjs';
17
19
  import { cacheProperties } from './Object/defaultValues.mjs';
18
20
 
19
- // @TODO this code is terrible and Line should be a special case of polyline.
20
-
21
21
  const coordProps = ['x1', 'x2', 'y1', 'y2'];
22
- /**
23
- * A Class to draw a line
24
- * A bunch of methods will be added to Polyline to handle the line case
25
- * The line class is very strange to work with, is all special, it hardly aligns
26
- * to what a developer want everytime there is an angle
27
- * @deprecated
28
- */
29
22
  class Line extends FabricObject {
30
- /**
31
- * Constructor
32
- * @param {Array} [points] Array of points
33
- * @param {Object} [options] Options object
34
- * @return {Line} thisArg
35
- */
36
23
  constructor() {
37
- let [x1, y1, x2, y2] = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : [0, 0, 0, 0];
24
+ let [x1, y1, x2, y2] = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : [0, 0, 100, 0];
38
25
  let options = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
39
26
  super();
40
- Object.assign(this, Line.ownDefaults);
27
+ _defineProperty(this, "hitStrokeWidth", 'auto');
28
+ _defineProperty(this, "_updatingEndpoints", false);
29
+ _defineProperty(this, "_useEndpointCoords", true);
30
+ _defineProperty(this, "_exportingSVG", false);
41
31
  this.setOptions(options);
42
32
  this.x1 = x1;
43
33
  this.x2 = x2;
44
34
  this.y1 = y1;
45
35
  this.y2 = y2;
36
+ if (options.hitStrokeWidth !== undefined) {
37
+ this.hitStrokeWidth = options.hitStrokeWidth;
38
+ }
39
+ this.hasBorders = false;
40
+ this.hasControls = true;
41
+ this.selectable = true;
42
+ this.hoverCursor = 'move';
43
+ this.perPixelTargetFind = false;
44
+ this.strokeLineCap = 'butt';
46
45
  this._setWidthHeight();
47
46
  const {
48
47
  left,
@@ -50,129 +49,384 @@ class Line extends FabricObject {
50
49
  } = options;
51
50
  typeof left === 'number' && this.set(LEFT, left);
52
51
  typeof top === 'number' && this.set(TOP, top);
52
+ this._setupLineControls();
53
+ }
54
+ _setupLineControls() {
55
+ this.controls = {
56
+ p1: new Control({
57
+ x: 0,
58
+ y: 0,
59
+ cursorStyle: 'move',
60
+ actionHandler: this._endpointActionHandler.bind(this),
61
+ positionHandler: this._p1PositionHandler.bind(this),
62
+ render: this._renderEndpointControl.bind(this),
63
+ sizeX: 12,
64
+ sizeY: 12
65
+ }),
66
+ p2: new Control({
67
+ x: 0,
68
+ y: 0,
69
+ cursorStyle: 'move',
70
+ actionHandler: this._endpointActionHandler.bind(this),
71
+ positionHandler: this._p2PositionHandler.bind(this),
72
+ render: this._renderEndpointControl.bind(this),
73
+ sizeX: 12,
74
+ sizeY: 12
75
+ })
76
+ };
77
+ }
78
+ _p1PositionHandler() {
79
+ return new Point(this.x1, this.y1).transform(this.getViewportTransform());
80
+ }
81
+ _p2PositionHandler() {
82
+ return new Point(this.x2, this.y2).transform(this.getViewportTransform());
83
+ }
84
+ _renderEndpointControl(ctx, left, top) {
85
+ const size = 12;
86
+ ctx.save();
87
+ ctx.fillStyle = '#007bff';
88
+ ctx.strokeStyle = '#ffffff';
89
+ ctx.lineWidth = 2;
90
+ ctx.beginPath();
91
+ ctx.arc(left, top, size / 2, 0, 2 * Math.PI);
92
+ ctx.fill();
93
+ ctx.stroke();
94
+ ctx.restore();
95
+ }
96
+ drawBorders(ctx) {
97
+ let styleOverride = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
98
+ if (this._useEndpointCoords) {
99
+ this._drawLineBorders(ctx, styleOverride);
100
+ return this;
101
+ }
102
+ return super.drawBorders(ctx, styleOverride, {});
103
+ }
104
+ _drawLineBorders(ctx) {
105
+ var _this$canvas;
106
+ let styleOverride = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
107
+ const vpt = ((_this$canvas = this.canvas) === null || _this$canvas === void 0 ? void 0 : _this$canvas.viewportTransform) || [1, 0, 0, 1, 0, 0];
108
+ ctx.save();
109
+ ctx.setTransform(vpt[0], vpt[1], vpt[2], vpt[3], vpt[4], vpt[5]);
110
+ ctx.strokeStyle = styleOverride.borderColor || this.borderColor || 'rgba(100, 200, 200, 0.5)';
111
+ ctx.lineWidth = (this.strokeWidth || 1) + 5;
112
+ ctx.lineCap = this.strokeLineCap || 'butt';
113
+ ctx.globalAlpha = this.isMoving ? this.borderOpacityWhenMoving : 1;
114
+ ctx.beginPath();
115
+ ctx.moveTo(this.x1, this.y1);
116
+ ctx.lineTo(this.x2, this.y2);
117
+ ctx.stroke();
118
+ ctx.restore();
119
+ }
120
+ _renderControls(ctx) {
121
+ let styleOverride = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
122
+ ctx.save();
123
+ ctx.globalAlpha = this.isMoving ? this.borderOpacityWhenMoving : 1;
124
+ this.drawControls(ctx, styleOverride);
125
+ ctx.restore();
53
126
  }
127
+ getBoundingRect() {
128
+ if (this._useEndpointCoords) {
129
+ const {
130
+ x1,
131
+ y1,
132
+ x2,
133
+ y2
134
+ } = this;
135
+ const effectiveStrokeWidth = this.hitStrokeWidth === 'auto' ? this.strokeWidth : this.hitStrokeWidth;
136
+ const padding = Math.max(effectiveStrokeWidth / 2 + 5, 10);
137
+ return {
138
+ left: Math.min(x1, x2) - padding,
139
+ top: Math.min(y1, y2) - padding,
140
+ width: Math.abs(x2 - x1) + padding * 2 || padding * 2,
141
+ height: Math.abs(y2 - y1) + padding * 2 || padding * 2
142
+ };
143
+ }
144
+ return super.getBoundingRect();
145
+ }
146
+ setCoords() {
147
+ if (this._useEndpointCoords) {
148
+ // Set width and height for hit detection and bounding box
149
+ const effectiveStrokeWidth = this.hitStrokeWidth === 'auto' ? this.strokeWidth : this.hitStrokeWidth;
150
+ const hitPadding = Math.max(effectiveStrokeWidth / 2 + 5, 10);
151
+ this.width = Math.abs(this.x2 - this.x1) + hitPadding * 2;
152
+ this.height = Math.abs(this.y2 - this.y1) + hitPadding * 2;
54
153
 
55
- /**
56
- * @private
57
- * @param {Object} [options] Options
58
- */
59
- _setWidthHeight() {
60
- const {
61
- x1,
62
- y1,
63
- x2,
64
- y2
65
- } = this;
66
- this.width = Math.abs(x2 - x1);
67
- this.height = Math.abs(y2 - y1);
68
- const {
69
- left,
70
- top,
71
- width,
72
- height
73
- } = makeBoundingBoxFromPoints([{
74
- x: x1,
75
- y: y1
76
- }, {
77
- x: x2,
78
- y: y2
79
- }]);
80
- const position = new Point(left + width / 2, top + height / 2);
81
- this.setPositionByOrigin(position, CENTER, CENTER);
154
+ // Only update left/top if they haven't been explicitly set (e.g., during loading)
155
+ if (this.left === 0 && this.top === 0) {
156
+ const center = this._findCenterFromElement();
157
+ this.left = center.x;
158
+ this.top = center.y;
159
+ }
160
+ }
161
+ super.setCoords();
162
+ }
163
+ getCoords() {
164
+ if (this._useEndpointCoords) {
165
+ const deltaX = this.x2 - this.x1;
166
+ const deltaY = this.y2 - this.y1;
167
+ const length = Math.sqrt(deltaX * deltaX + deltaY * deltaY);
168
+ if (length === 0) {
169
+ return super.getCoords();
170
+ }
171
+ const effectiveStrokeWidth = this.hitStrokeWidth === 'auto' ? this.strokeWidth : this.hitStrokeWidth;
172
+ const halfWidth = Math.max(effectiveStrokeWidth / 2 + 2, 5);
173
+
174
+ // Unit vector perpendicular to line
175
+ const perpX = -deltaY / length;
176
+ const perpY = deltaX / length;
177
+
178
+ // Four corners of oriented rectangle
179
+ return [new Point(this.x1 + perpX * halfWidth, this.y1 + perpY * halfWidth), new Point(this.x2 + perpX * halfWidth, this.y2 + perpY * halfWidth), new Point(this.x2 - perpX * halfWidth, this.y2 - perpY * halfWidth), new Point(this.x1 - perpX * halfWidth, this.y1 - perpY * halfWidth)];
180
+ }
181
+ return super.getCoords();
182
+ }
183
+ containsPoint(point) {
184
+ if (this._useEndpointCoords) {
185
+ var _this$canvas2;
186
+ if (((_this$canvas2 = this.canvas) === null || _this$canvas2 === void 0 ? void 0 : _this$canvas2.getActiveObject()) === this) {
187
+ return super.containsPoint(point);
188
+ }
189
+ const distance = this._distanceToLineSegment(point.x, point.y);
190
+ const effectiveStrokeWidth = this.hitStrokeWidth === 'auto' ? this.strokeWidth : this.hitStrokeWidth || 1;
191
+ const tolerance = Math.max(effectiveStrokeWidth / 2 + 2, 5);
192
+ return distance <= tolerance;
193
+ }
194
+ return super.containsPoint(point);
195
+ }
196
+ _distanceToLineSegment(px, py) {
197
+ const x1 = this.x1,
198
+ y1 = this.y1,
199
+ x2 = this.x2,
200
+ y2 = this.y2;
201
+ const pd2 = (x1 - x2) * (x1 - x2) + (y1 - y2) * (y1 - y2);
202
+ if (pd2 === 0) {
203
+ return Math.sqrt((px - x1) * (px - x1) + (py - y1) * (py - y1));
204
+ }
205
+ const u = ((px - x1) * (x2 - x1) + (py - y1) * (y2 - y1)) / pd2;
206
+ let closestX, closestY;
207
+ if (u < 0) {
208
+ closestX = x1;
209
+ closestY = y1;
210
+ } else if (u > 1) {
211
+ closestX = x2;
212
+ closestY = y2;
213
+ } else {
214
+ closestX = x1 + u * (x2 - x1);
215
+ closestY = y1 + u * (y2 - y1);
216
+ }
217
+ return Math.sqrt((px - closestX) * (px - closestX) + (py - closestY) * (py - closestY));
82
218
  }
219
+ _endpointActionHandler(eventData, transformData, x, y) {
220
+ var _this$canvas4;
221
+ const controlKey = transformData.corner;
222
+ const pointer = new Point(x, y);
223
+ let newX = pointer.x;
224
+ let newY = pointer.y;
225
+ if (eventData.shiftKey) {
226
+ const otherControl = controlKey === 'p1' ? 'p2' : 'p1';
227
+ const otherX = this[otherControl === 'p1' ? 'x1' : 'x2'];
228
+ const otherY = this[otherControl === 'p1' ? 'y1' : 'y2'];
229
+ const snapped = this._snapToAngle(otherX, otherY, newX, newY);
230
+ newX = snapped.x;
231
+ newY = snapped.y;
232
+ }
233
+ if (this._useEndpointCoords) {
234
+ var _this$canvas3;
235
+ if (controlKey === 'p1') {
236
+ this.x1 = newX;
237
+ this.y1 = newY;
238
+ } else if (controlKey === 'p2') {
239
+ this.x2 = newX;
240
+ this.y2 = newY;
241
+ }
83
242
 
84
- /**
85
- * @private
86
- * @param {String} key
87
- * @param {*} value
88
- */
243
+ // Update gradient coordinates if stroke is a gradient (but not during SVG export)
244
+ if (this.stroke instanceof Gradient && !this._exportingSVG) {
245
+ this.stroke.coords.x1 = this.x1;
246
+ this.stroke.coords.y1 = this.y1;
247
+ this.stroke.coords.x2 = this.x2;
248
+ this.stroke.coords.y2 = this.y2;
249
+ }
250
+ this.dirty = true;
251
+ this.setCoords();
252
+ (_this$canvas3 = this.canvas) === null || _this$canvas3 === void 0 || _this$canvas3.requestRenderAll();
253
+ return true;
254
+ }
255
+
256
+ // Fallback for old system
257
+ this._updatingEndpoints = true;
258
+ if (controlKey === 'p1') {
259
+ this.x1 = newX;
260
+ this.y1 = newY;
261
+ } else if (controlKey === 'p2') {
262
+ this.x2 = newX;
263
+ this.y2 = newY;
264
+ }
265
+ this._setWidthHeight();
266
+ this.dirty = true;
267
+ this._updatingEndpoints = false;
268
+ (_this$canvas4 = this.canvas) === null || _this$canvas4 === void 0 || _this$canvas4.requestRenderAll();
269
+ this.fire('modified', {
270
+ transform: transformData,
271
+ target: this,
272
+ e: eventData
273
+ });
274
+ return true;
275
+ }
276
+ _snapToAngle(fromX, fromY, toX, toY) {
277
+ const deltaX = toX - fromX;
278
+ const deltaY = toY - fromY;
279
+ const distance = Math.sqrt(deltaX * deltaX + deltaY * deltaY);
280
+ if (distance === 0) return {
281
+ x: toX,
282
+ y: toY
283
+ };
284
+ let angle = Math.atan2(deltaY, deltaX) * (180 / Math.PI);
285
+ const snapIncrement = 15;
286
+ const snappedAngle = Math.round(angle / snapIncrement) * snapIncrement;
287
+ const snappedRadians = snappedAngle * (Math.PI / 180);
288
+ return {
289
+ x: fromX + Math.cos(snappedRadians) * distance,
290
+ y: fromY + Math.sin(snappedRadians) * distance
291
+ };
292
+ }
293
+ _setWidthHeight() {
294
+ let skipReposition = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : false;
295
+ this.width = Math.abs(this.x2 - this.x1) || 1;
296
+ this.height = Math.abs(this.y2 - this.y1) || 1;
297
+ if (!skipReposition && !this._updatingEndpoints) {
298
+ const {
299
+ left,
300
+ top,
301
+ width,
302
+ height
303
+ } = makeBoundingBoxFromPoints([{
304
+ x: this.x1,
305
+ y: this.y1
306
+ }, {
307
+ x: this.x2,
308
+ y: this.y2
309
+ }]);
310
+ this.setPositionByOrigin(new Point(left + width / 2, top + height / 2), CENTER, CENTER);
311
+ }
312
+ }
89
313
  _set(key, value) {
314
+ const oldLeft = this.left;
315
+ const oldTop = this.top;
90
316
  super._set(key, value);
91
317
  if (coordProps.includes(key)) {
92
- // this doesn't make sense very much, since setting x1 when top or left
93
- // are already set, is just going to show a strange result since the
94
- // line will move way more than the developer expect.
95
- // in fabric5 it worked only when the line didn't have extra transformations,
96
- // in fabric6 too. With extra transform they behave bad in different ways.
97
- // This needs probably a good rework or a tutorial if you have to create a dynamic line
98
318
  this._setWidthHeight();
319
+ this.dirty = true;
320
+
321
+ // Update gradient coordinates if stroke is a gradient (but not during SVG export)
322
+ if (this.stroke instanceof Gradient && !this._exportingSVG) {
323
+ this.stroke.coords.x1 = this.x1;
324
+ this.stroke.coords.y1 = this.y1;
325
+ this.stroke.coords.x2 = this.x2;
326
+ this.stroke.coords.y2 = this.y2;
327
+ }
328
+ }
329
+ if ((key === 'left' || key === 'top') && this.canvas && !this._updatingEndpoints) {
330
+ const deltaX = this.left - oldLeft;
331
+ const deltaY = this.top - oldTop;
332
+ if (deltaX !== 0 || deltaY !== 0) {
333
+ this._updatingEndpoints = true;
334
+ this.x1 += deltaX;
335
+ this.y1 += deltaY;
336
+ this.x2 += deltaX;
337
+ this.y2 += deltaY;
338
+
339
+ // Update gradient coordinates if stroke is a gradient
340
+ if (this.stroke instanceof Gradient) {
341
+ this.stroke.coords.x1 = this.x1;
342
+ this.stroke.coords.y1 = this.y1;
343
+ this.stroke.coords.x2 = this.x2;
344
+ this.stroke.coords.y2 = this.y2;
345
+ }
346
+ this._updatingEndpoints = false;
347
+ }
99
348
  }
100
349
  return this;
101
350
  }
102
-
103
- /**
104
- * @private
105
- * @param {CanvasRenderingContext2D} ctx Context to render on
106
- */
351
+ render(ctx) {
352
+ if (this._useEndpointCoords) {
353
+ this._renderDirectly(ctx);
354
+ return;
355
+ }
356
+ super.render(ctx);
357
+ }
358
+ _renderDirectly(ctx) {
359
+ if (!this.visible) return;
360
+ ctx.save();
361
+ ctx.globalAlpha = this.opacity;
362
+ ctx.lineWidth = this.strokeWidth;
363
+ ctx.lineCap = this.strokeLineCap || 'butt';
364
+ ctx.beginPath();
365
+ ctx.moveTo(this.x1, this.y1);
366
+ ctx.lineTo(this.x2, this.y2);
367
+ const origStrokeStyle = ctx.strokeStyle;
368
+ if (isFiller(this.stroke)) {
369
+ ctx.strokeStyle = this.stroke.toLive(ctx);
370
+ } else {
371
+ var _this$stroke;
372
+ ctx.strokeStyle = ((_this$stroke = this.stroke) === null || _this$stroke === void 0 ? void 0 : _this$stroke.toString()) || '#000';
373
+ }
374
+ ctx.stroke();
375
+ ctx.strokeStyle = origStrokeStyle;
376
+ ctx.restore();
377
+ }
107
378
  _render(ctx) {
379
+ if (this._useEndpointCoords) return;
108
380
  ctx.beginPath();
109
381
  const p = this.calcLinePoints();
110
382
  ctx.moveTo(p.x1, p.y1);
111
383
  ctx.lineTo(p.x2, p.y2);
112
384
  ctx.lineWidth = this.strokeWidth;
113
-
114
- // TODO: test this
115
- // make sure setting "fill" changes color of a line
116
- // (by copying fillStyle to strokeStyle, since line is stroked, not filled)
117
385
  const origStrokeStyle = ctx.strokeStyle;
118
386
  if (isFiller(this.stroke)) {
119
387
  ctx.strokeStyle = this.stroke.toLive(ctx);
120
- } else {
121
- var _this$stroke;
122
- ctx.strokeStyle = (_this$stroke = this.stroke) !== null && _this$stroke !== void 0 ? _this$stroke : ctx.fillStyle;
123
388
  }
124
389
  this.stroke && this._renderStroke(ctx);
125
390
  ctx.strokeStyle = origStrokeStyle;
126
391
  }
127
-
128
- /**
129
- * This function is an helper for svg import. it returns the center of the object in the svg
130
- * untransformed coordinates
131
- * @private
132
- * @return {Point} center point from element coordinates
133
- */
134
392
  _findCenterFromElement() {
135
393
  return new Point((this.x1 + this.x2) / 2, (this.y1 + this.y2) / 2);
136
394
  }
137
-
138
- /**
139
- * Returns object representation of an instance
140
- * @param {Array} [propertiesToInclude] Any properties that you might want to additionally include in the output
141
- * @return {Object} object representation of an instance
142
- */
143
395
  toObject() {
144
396
  let propertiesToInclude = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : [];
397
+ if (this._useEndpointCoords) {
398
+ return {
399
+ ...super.toObject(propertiesToInclude),
400
+ x1: this.x1,
401
+ y1: this.y1,
402
+ x2: this.x2,
403
+ y2: this.y2
404
+ };
405
+ }
145
406
  return {
146
407
  ...super.toObject(propertiesToInclude),
147
408
  ...this.calcLinePoints()
148
409
  };
149
410
  }
150
-
151
- /*
152
- * Calculate object dimensions from its properties
153
- * @private
154
- */
155
411
  _getNonTransformedDimensions() {
156
412
  const dim = super._getNonTransformedDimensions();
157
- if (this.strokeLineCap === 'butt') {
158
- if (this.width === 0) {
159
- dim.y -= this.strokeWidth;
160
- }
161
- if (this.height === 0) {
162
- dim.x -= this.strokeWidth;
163
- }
413
+ if (this.strokeLineCap === 'round') {
414
+ dim.x += this.strokeWidth;
415
+ dim.y += this.strokeWidth;
164
416
  }
165
417
  return dim;
166
418
  }
167
-
168
- /**
169
- * Recalculates line points given width and height
170
- * Those points are simply placed around the center,
171
- * This is not useful outside internal render functions and svg output
172
- * Is not meant to be for the developer.
173
- * @private
174
- */
175
419
  calcLinePoints() {
420
+ if (this._updatingEndpoints) {
421
+ const centerX = (this.x1 + this.x2) / 2;
422
+ const centerY = (this.y1 + this.y2) / 2;
423
+ return {
424
+ x1: this.x1 - centerX,
425
+ y1: this.y1 - centerY,
426
+ x2: this.x2 - centerX,
427
+ y2: this.y2 - centerY
428
+ };
429
+ }
176
430
  const {
177
431
  x1: _x1,
178
432
  x2: _x2,
@@ -181,48 +435,64 @@ class Line extends FabricObject {
181
435
  width,
182
436
  height
183
437
  } = this;
184
- const xMult = _x1 <= _x2 ? -1 : 1,
185
- yMult = _y1 <= _y2 ? -1 : 1,
186
- x1 = xMult * width / 2,
187
- y1 = yMult * height / 2,
188
- x2 = xMult * -width / 2,
189
- y2 = yMult * -height / 2;
438
+ const xMult = _x1 <= _x2 ? -1 : 1;
439
+ const yMult = _y1 <= _y2 ? -1 : 1;
190
440
  return {
191
- x1,
192
- x2,
193
- y1,
194
- y2
441
+ x1: xMult * width / 2,
442
+ y1: yMult * height / 2,
443
+ x2: xMult * -width / 2,
444
+ y2: yMult * -height / 2
195
445
  };
196
446
  }
197
-
198
- /* _FROM_SVG_START_ */
199
-
200
- /**
201
- * Returns svg representation of an instance
202
- * @return {Array} an array of strings with the specific svg representation
203
- * of the instance
204
- */
205
447
  _toSVG() {
206
- const {
207
- x1,
208
- x2,
209
- y1,
210
- y2
211
- } = this.calcLinePoints();
212
- return ['<line ', 'COMMON_PARTS', `x1="${x1}" y1="${y1}" x2="${x2}" y2="${y2}" />\n`];
448
+ if (this._useEndpointCoords) {
449
+ // Use absolute coordinates to bypass all Fabric.js transforms
450
+ // Handle gradients manually for proper SVG export
451
+ let strokeAttr = '';
452
+ if (this.stroke instanceof Gradient) {
453
+ // Let Fabric.js handle gradient definition, but we'll use the reference
454
+ strokeAttr = `stroke="url(#${this.stroke.id})"`;
455
+ } else {
456
+ strokeAttr = `stroke="${this.stroke || 'none'}"`;
457
+ }
458
+ return [`<line ${strokeAttr} stroke-width="${this.strokeWidth}" stroke-linecap="${this.strokeLineCap}" `, `stroke-dasharray="${this.strokeDashArray ? this.strokeDashArray.join(' ') : 'none'}" `, `stroke-dashoffset="${this.strokeDashOffset}" stroke-linejoin="${this.strokeLineJoin}" `, `stroke-miterlimit="${this.strokeMiterLimit}" fill="${this.fill || 'none'}" `, `fill-rule="${this.fillRule}" opacity="${this.opacity}" `, `x1="${this.x1}" y1="${this.y1}" x2="${this.x2}" y2="${this.y2}" />\n`];
459
+ } else {
460
+ // Use standard calcLinePoints for legacy mode
461
+ const {
462
+ x1,
463
+ x2,
464
+ y1,
465
+ y2
466
+ } = this.calcLinePoints();
467
+ return ['<line ', 'COMMON_PARTS', `x1="${x1}" y1="${y1}" x2="${x2}" y2="${y2}" />\n`];
468
+ }
213
469
  }
470
+ toSVG(reviver) {
471
+ if (this._useEndpointCoords) {
472
+ // For endpoint coords, we need to bypass transforms but still allow gradients
473
+ // Let's temporarily disable transforms during SVG generation
474
+ const originalLeft = this.left;
475
+ const originalTop = this.top;
214
476
 
215
- /**
216
- * List of attribute names to account for when parsing SVG element (used by {@link Line.fromElement})
217
- * @see http://www.w3.org/TR/SVG/shapes.html#LineElement
218
- */
477
+ // Set position to center of line for gradient calculation
478
+ this.left = (this.x1 + this.x2) / 2;
479
+ this.top = (this.y1 + this.y2) / 2;
219
480
 
220
- /**
221
- * Returns Line instance from an SVG element
222
- * @param {HTMLElement} element Element to parse
223
- * @param {Object} [options] Options object
224
- * @param {Function} [callback] callback function invoked after parsing
225
- */
481
+ // Get the SVG with standard system (for gradient handling)
482
+ const standardSVG = super.toSVG(reviver);
483
+
484
+ // Restore original position
485
+ this.left = originalLeft;
486
+ this.top = originalTop;
487
+
488
+ // Extract gradient definition and clean up the line element
489
+ // Remove the transform wrapper and update coordinates
490
+ const cleanSVG = standardSVG.replace(/<g transform="[^"]*"[^>]*>/g, '').replace(/<\/g>/g, '').replace(/x1="[^"]*"/g, `x1="${this.x1}"`).replace(/y1="[^"]*"/g, `y1="${this.y1}"`).replace(/x2="[^"]*"/g, `x2="${this.x2}"`).replace(/y2="[^"]*"/g, `y2="${this.y2}"`);
491
+ return cleanSVG;
492
+ }
493
+ // Use default behavior for legacy mode
494
+ return super.toSVG(reviver);
495
+ }
226
496
  static async fromElement(element, options, cssRules) {
227
497
  const {
228
498
  x1 = 0,
@@ -233,14 +503,6 @@ class Line extends FabricObject {
233
503
  } = parseAttributes(element, this.ATTRIBUTE_NAMES, cssRules);
234
504
  return new this([x1, y1, x2, y2], parsedAttributes);
235
505
  }
236
-
237
- /* _FROM_SVG_END_ */
238
-
239
- /**
240
- * Returns Line instance from an object representation
241
- * @param {Object} object Object to create an instance from
242
- * @returns {Promise<Line>}
243
- */
244
506
  static fromObject(_ref) {
245
507
  let {
246
508
  x1,
@@ -257,22 +519,6 @@ class Line extends FabricObject {
257
519
  });
258
520
  }
259
521
  }
260
- /**
261
- * x value or first line edge
262
- * @type number
263
- */
264
- /**
265
- * y value or first line edge
266
- * @type number
267
- */
268
- /**
269
- * x value or second line edge
270
- * @type number
271
- */
272
- /**
273
- * y value or second line edge
274
- * @type number
275
- */
276
522
  _defineProperty(Line, "type", 'Line');
277
523
  _defineProperty(Line, "cacheProperties", [...cacheProperties, ...coordProps]);
278
524
  _defineProperty(Line, "ATTRIBUTE_NAMES", SHARED_ATTRIBUTES.concat(coordProps));