@nasser-sw/fabric 7.0.1-beta7 → 7.0.1-beta9

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 (148) hide show
  1. package/debug/konva-master/CHANGELOG.md +1475 -0
  2. package/debug/konva-master/LICENSE +22 -0
  3. package/debug/konva-master/README.md +209 -0
  4. package/debug/konva-master/gulpfile.mjs +110 -0
  5. package/debug/konva-master/package.json +139 -0
  6. package/debug/konva-master/release.sh +62 -0
  7. package/debug/konva-master/resources/doc-includes/ContainerParams.txt +6 -0
  8. package/debug/konva-master/resources/doc-includes/NodeParams.txt +20 -0
  9. package/debug/konva-master/resources/doc-includes/ShapeParams.txt +53 -0
  10. package/debug/konva-master/resources/jsdoc.conf.json +28 -0
  11. package/debug/konva-master/rollup.config.mjs +32 -0
  12. package/debug/konva-master/src/Animation.ts +237 -0
  13. package/debug/konva-master/src/BezierFunctions.ts +826 -0
  14. package/debug/konva-master/src/Canvas.ts +230 -0
  15. package/debug/konva-master/src/Container.ts +649 -0
  16. package/debug/konva-master/src/Context.ts +1017 -0
  17. package/debug/konva-master/src/Core.ts +5 -0
  18. package/debug/konva-master/src/DragAndDrop.ts +173 -0
  19. package/debug/konva-master/src/Factory.ts +246 -0
  20. package/debug/konva-master/src/FastLayer.ts +29 -0
  21. package/debug/konva-master/src/Global.ts +210 -0
  22. package/debug/konva-master/src/Group.ts +31 -0
  23. package/debug/konva-master/src/Layer.ts +546 -0
  24. package/debug/konva-master/src/Node.ts +3477 -0
  25. package/debug/konva-master/src/PointerEvents.ts +67 -0
  26. package/debug/konva-master/src/Shape.ts +2081 -0
  27. package/debug/konva-master/src/Stage.ts +1000 -0
  28. package/debug/konva-master/src/Tween.ts +811 -0
  29. package/debug/konva-master/src/Util.ts +1123 -0
  30. package/debug/konva-master/src/Validators.ts +210 -0
  31. package/debug/konva-master/src/_CoreInternals.ts +85 -0
  32. package/debug/konva-master/src/_FullInternals.ts +171 -0
  33. package/debug/konva-master/src/canvas-backend.ts +36 -0
  34. package/debug/konva-master/src/filters/Blur.ts +388 -0
  35. package/debug/konva-master/src/filters/Brighten.ts +48 -0
  36. package/debug/konva-master/src/filters/Brightness.ts +30 -0
  37. package/debug/konva-master/src/filters/Contrast.ts +75 -0
  38. package/debug/konva-master/src/filters/Emboss.ts +207 -0
  39. package/debug/konva-master/src/filters/Enhance.ts +154 -0
  40. package/debug/konva-master/src/filters/Grayscale.ts +25 -0
  41. package/debug/konva-master/src/filters/HSL.ts +108 -0
  42. package/debug/konva-master/src/filters/HSV.ts +106 -0
  43. package/debug/konva-master/src/filters/Invert.ts +23 -0
  44. package/debug/konva-master/src/filters/Kaleidoscope.ts +274 -0
  45. package/debug/konva-master/src/filters/Mask.ts +220 -0
  46. package/debug/konva-master/src/filters/Noise.ts +44 -0
  47. package/debug/konva-master/src/filters/Pixelate.ts +107 -0
  48. package/debug/konva-master/src/filters/Posterize.ts +46 -0
  49. package/debug/konva-master/src/filters/RGB.ts +82 -0
  50. package/debug/konva-master/src/filters/RGBA.ts +103 -0
  51. package/debug/konva-master/src/filters/Sepia.ts +27 -0
  52. package/debug/konva-master/src/filters/Solarize.ts +29 -0
  53. package/debug/konva-master/src/filters/Threshold.ts +44 -0
  54. package/debug/konva-master/src/index.ts +3 -0
  55. package/debug/konva-master/src/shapes/Arc.ts +176 -0
  56. package/debug/konva-master/src/shapes/Arrow.ts +231 -0
  57. package/debug/konva-master/src/shapes/Circle.ts +76 -0
  58. package/debug/konva-master/src/shapes/Ellipse.ts +121 -0
  59. package/debug/konva-master/src/shapes/Image.ts +319 -0
  60. package/debug/konva-master/src/shapes/Label.ts +386 -0
  61. package/debug/konva-master/src/shapes/Line.ts +364 -0
  62. package/debug/konva-master/src/shapes/Path.ts +1013 -0
  63. package/debug/konva-master/src/shapes/Rect.ts +79 -0
  64. package/debug/konva-master/src/shapes/RegularPolygon.ts +167 -0
  65. package/debug/konva-master/src/shapes/Ring.ts +94 -0
  66. package/debug/konva-master/src/shapes/Sprite.ts +370 -0
  67. package/debug/konva-master/src/shapes/Star.ts +125 -0
  68. package/debug/konva-master/src/shapes/Text.ts +1065 -0
  69. package/debug/konva-master/src/shapes/TextPath.ts +583 -0
  70. package/debug/konva-master/src/shapes/Transformer.ts +1889 -0
  71. package/debug/konva-master/src/shapes/Wedge.ts +129 -0
  72. package/debug/konva-master/src/skia-backend.ts +35 -0
  73. package/debug/konva-master/src/types.ts +84 -0
  74. package/debug/konva-master/tsconfig.json +31 -0
  75. package/debug/konva-master/tsconfig.test.json +7 -0
  76. package/dist/index.js +977 -29
  77. package/dist/index.js.map +1 -1
  78. package/dist/index.min.js +1 -1
  79. package/dist/index.min.js.map +1 -1
  80. package/dist/index.min.mjs +1 -1
  81. package/dist/index.min.mjs.map +1 -1
  82. package/dist/index.mjs +977 -29
  83. package/dist/index.mjs.map +1 -1
  84. package/dist/index.node.cjs +977 -29
  85. package/dist/index.node.cjs.map +1 -1
  86. package/dist/index.node.mjs +977 -29
  87. package/dist/index.node.mjs.map +1 -1
  88. package/dist/package.json.min.mjs +1 -1
  89. package/dist/package.json.mjs +1 -1
  90. package/dist/src/shapes/Line.d.ts +1 -0
  91. package/dist/src/shapes/Line.d.ts.map +1 -1
  92. package/dist/src/shapes/Line.min.mjs +1 -1
  93. package/dist/src/shapes/Line.min.mjs.map +1 -1
  94. package/dist/src/shapes/Line.mjs +63 -6
  95. package/dist/src/shapes/Line.mjs.map +1 -1
  96. package/dist/src/shapes/Text/Text.d.ts +19 -0
  97. package/dist/src/shapes/Text/Text.d.ts.map +1 -1
  98. package/dist/src/shapes/Text/Text.min.mjs +1 -1
  99. package/dist/src/shapes/Text/Text.min.mjs.map +1 -1
  100. package/dist/src/shapes/Text/Text.mjs +238 -4
  101. package/dist/src/shapes/Text/Text.mjs.map +1 -1
  102. package/dist/src/shapes/Textbox.d.ts +38 -1
  103. package/dist/src/shapes/Textbox.d.ts.map +1 -1
  104. package/dist/src/shapes/Textbox.min.mjs +1 -1
  105. package/dist/src/shapes/Textbox.min.mjs.map +1 -1
  106. package/dist/src/shapes/Textbox.mjs +497 -15
  107. package/dist/src/shapes/Textbox.mjs.map +1 -1
  108. package/dist/src/text/examples/arabicTextExample.d.ts +60 -0
  109. package/dist/src/text/examples/arabicTextExample.d.ts.map +1 -0
  110. package/dist/src/text/measure.d.ts +9 -0
  111. package/dist/src/text/measure.d.ts.map +1 -1
  112. package/dist/src/text/measure.min.mjs +1 -1
  113. package/dist/src/text/measure.min.mjs.map +1 -1
  114. package/dist/src/text/measure.mjs +175 -4
  115. package/dist/src/text/measure.mjs.map +1 -1
  116. package/dist/src/text/overlayEditor.d.ts.map +1 -1
  117. package/dist/src/text/overlayEditor.min.mjs +1 -1
  118. package/dist/src/text/overlayEditor.min.mjs.map +1 -1
  119. package/dist/src/text/overlayEditor.mjs +7 -0
  120. package/dist/src/text/overlayEditor.mjs.map +1 -1
  121. package/dist/src/text/scriptUtils.d.ts +142 -0
  122. package/dist/src/text/scriptUtils.d.ts.map +1 -0
  123. package/dist/src/text/scriptUtils.min.mjs +2 -0
  124. package/dist/src/text/scriptUtils.min.mjs.map +1 -0
  125. package/dist/src/text/scriptUtils.mjs +212 -0
  126. package/dist/src/text/scriptUtils.mjs.map +1 -0
  127. package/dist-extensions/src/shapes/Line.d.ts +1 -0
  128. package/dist-extensions/src/shapes/Line.d.ts.map +1 -1
  129. package/dist-extensions/src/shapes/Text/Text.d.ts +19 -0
  130. package/dist-extensions/src/shapes/Text/Text.d.ts.map +1 -1
  131. package/dist-extensions/src/shapes/Textbox.d.ts +38 -1
  132. package/dist-extensions/src/shapes/Textbox.d.ts.map +1 -1
  133. package/dist-extensions/src/text/measure.d.ts +9 -0
  134. package/dist-extensions/src/text/measure.d.ts.map +1 -1
  135. package/dist-extensions/src/text/overlayEditor.d.ts.map +1 -1
  136. package/dist-extensions/src/text/scriptUtils.d.ts +142 -0
  137. package/dist-extensions/src/text/scriptUtils.d.ts.map +1 -0
  138. package/fabric-test-editor.html +2401 -46
  139. package/fabric-test2.html +43 -0
  140. package/fonts/STV Bold.ttf +0 -0
  141. package/fonts/STV Light.ttf +0 -0
  142. package/fonts/STV Regular.ttf +0 -0
  143. package/package.json +1 -1
  144. package/src/shapes/Line.ts +132 -46
  145. package/src/shapes/Text/Text.ts +238 -5
  146. package/src/shapes/Textbox.ts +521 -11
  147. package/src/text/measure.ts +200 -50
  148. package/src/text/overlayEditor.ts +7 -0
package/fabric-test2.html CHANGED
@@ -50,6 +50,7 @@
50
50
 
51
51
  <div class="controls">
52
52
  <button id="addLineBtn">Add Line</button>
53
+ <button id="addGradientLineBtn">Add Gradient Line</button>
53
54
  <button id="clearCanvasBtn">Clear Canvas</button>
54
55
  <button id="toggleDebugBtn">Toggle Debug</button>
55
56
  <button id="exportPngBtn">Export as PNG</button>
@@ -116,6 +117,48 @@
116
117
  lineCounter++;
117
118
  });
118
119
 
120
+ // Add Gradient Line button
121
+ document.getElementById('addGradientLineBtn').addEventListener('click', () => {
122
+ // Line coordinates
123
+ const x1 = 150, y1 = 120, x2 = 450, y2 = 280;
124
+
125
+ // Create a linear gradient that follows the line direction using absolute coordinates
126
+ const gradient = new fabric.Gradient({
127
+ type: 'linear',
128
+ gradientUnits: 'pixels',
129
+ coords: {
130
+ x1: x1,
131
+ y1: y1,
132
+ x2: x2,
133
+ y2: y2
134
+ },
135
+ colorStops: [
136
+ { offset: 0, color: '#ff0000' },
137
+ { offset: 0.5, color: '#00ff00' },
138
+ { offset: 1, color: '#0000ff' }
139
+ ]
140
+ });
141
+
142
+ // Create a line with gradient stroke
143
+ const line = new fabric.Line([x1, y1, x2, y2], {
144
+ stroke: gradient,
145
+ strokeWidth: 8,
146
+ strokeLineCap: 'round',
147
+ selectable: true,
148
+ evented: true
149
+ });
150
+
151
+ canvas.add(line);
152
+ canvas.setActiveObject(line);
153
+ canvas.renderAll();
154
+
155
+ console.log('Added gradient line:', line);
156
+ console.log('Gradient object:', gradient);
157
+ console.log('Line coordinates:', { x1, y1, x2, y2 });
158
+ console.log('Gradient coordinates:', gradient.coords);
159
+ lineCounter++;
160
+ });
161
+
119
162
  // Clear Canvas button
120
163
  document.getElementById('clearCanvasBtn').addEventListener('click', () => {
121
164
  canvas.clear();
Binary file
Binary file
Binary file
package/package.json CHANGED
@@ -2,7 +2,7 @@
2
2
  "name": "@nasser-sw/fabric",
3
3
  "description": "Object model for HTML5 canvas, and SVG-to-canvas parser. Backed by jsdom and node-canvas.",
4
4
  "homepage": "http://fabricjs.com/",
5
- "version": "7.0.1-beta7",
5
+ "version": "7.0.1-beta9",
6
6
  "author": "Juriy Zaytsev <kangax@gmail.com>",
7
7
  "contributors": [
8
8
  {
@@ -12,7 +12,7 @@ import { CENTER, LEFT, TOP } from '../constants';
12
12
  import type { CSSRules } from '../parser/typedefs';
13
13
  import { Control } from '../controls/Control';
14
14
  import type { TPointerEvent, Transform } from '../EventTypeDefs';
15
- import { multiplyTransformMatrices } from '../util/misc/matrix';
15
+ import { Gradient } from '../gradient/Gradient';
16
16
 
17
17
  const coordProps = ['x1', 'x2', 'y1', 'y2'] as const;
18
18
 
@@ -27,10 +27,10 @@ export interface SerializedLineProps
27
27
  extends SerializedObjectProps,
28
28
  UniqueLineCoords {}
29
29
 
30
- export class Line<
30
+ export class Line<
31
31
  Props extends TOptions<FabricObjectProps> = Partial<FabricObjectProps>,
32
32
  SProps extends SerializedLineProps = SerializedLineProps,
33
- EventSpec extends ObjectEvents = ObjectEvents
33
+ EventSpec extends ObjectEvents = ObjectEvents,
34
34
  >
35
35
  extends FabricObject<Props, SProps, EventSpec>
36
36
  implements UniqueLineCoords
@@ -44,11 +44,15 @@ export class Line<
44
44
 
45
45
  private _updatingEndpoints = false;
46
46
  private _useEndpointCoords = true;
47
+ private _exportingSVG = false;
47
48
 
48
49
  static type = 'Line';
49
50
  static cacheProperties = [...cacheProperties, ...coordProps];
50
51
 
51
- constructor([x1, y1, x2, y2] = [0, 0, 100, 0], options: Partial<Props & {hitStrokeWidth?: number | 'auto'}> = {}) {
52
+ constructor(
53
+ [x1, y1, x2, y2] = [0, 0, 100, 0],
54
+ options: Partial<Props & { hitStrokeWidth?: number | 'auto' }> = {},
55
+ ) {
52
56
  super();
53
57
  this.setOptions(options);
54
58
  this.x1 = x1;
@@ -110,7 +114,7 @@ export class Line<
110
114
  _renderEndpointControl(
111
115
  ctx: CanvasRenderingContext2D,
112
116
  left: number,
113
- top: number
117
+ top: number,
114
118
  ) {
115
119
  const size = 12;
116
120
  ctx.save();
@@ -137,7 +141,9 @@ export class Line<
137
141
  ctx.save();
138
142
  ctx.setTransform(vpt[0], vpt[1], vpt[2], vpt[3], vpt[4], vpt[5]);
139
143
  ctx.strokeStyle =
140
- styleOverride.borderColor || this.borderColor || 'rgba(100, 200, 200, 0.5)';
144
+ styleOverride.borderColor ||
145
+ this.borderColor ||
146
+ 'rgba(100, 200, 200, 0.5)';
141
147
  ctx.lineWidth = (this.strokeWidth || 1) + 5;
142
148
  ctx.lineCap = this.strokeLineCap || 'butt';
143
149
  ctx.globalAlpha = this.isMoving ? this.borderOpacityWhenMoving : 1;
@@ -159,9 +165,7 @@ export class Line<
159
165
  if (this._useEndpointCoords) {
160
166
  const { x1, y1, x2, y2 } = this;
161
167
  const effectiveStrokeWidth =
162
- this.hitStrokeWidth === 'auto'
163
- ? this.strokeWidth
164
- : this.hitStrokeWidth;
168
+ this.hitStrokeWidth === 'auto' ? this.strokeWidth : this.hitStrokeWidth;
165
169
  const padding = Math.max(effectiveStrokeWidth / 2 + 5, 10);
166
170
  return {
167
171
  left: Math.min(x1, x2) - padding,
@@ -177,13 +181,11 @@ export class Line<
177
181
  if (this._useEndpointCoords) {
178
182
  // Set width and height for hit detection and bounding box
179
183
  const effectiveStrokeWidth =
180
- this.hitStrokeWidth === 'auto'
181
- ? this.strokeWidth
182
- : this.hitStrokeWidth;
184
+ this.hitStrokeWidth === 'auto' ? this.strokeWidth : this.hitStrokeWidth;
183
185
  const hitPadding = Math.max(effectiveStrokeWidth / 2 + 5, 10);
184
186
  this.width = Math.abs(this.x2 - this.x1) + hitPadding * 2;
185
187
  this.height = Math.abs(this.y2 - this.y1) + hitPadding * 2;
186
-
188
+
187
189
  // Only update left/top if they haven't been explicitly set (e.g., during loading)
188
190
  if (this.left === 0 && this.top === 0) {
189
191
  const center = this._findCenterFromElement();
@@ -199,20 +201,19 @@ export class Line<
199
201
  const deltaX = this.x2 - this.x1;
200
202
  const deltaY = this.y2 - this.y1;
201
203
  const length = Math.sqrt(deltaX * deltaX + deltaY * deltaY);
202
-
204
+
203
205
  if (length === 0) {
204
206
  return super.getCoords() as [Point, Point, Point, Point];
205
207
  }
206
-
207
- const effectiveStrokeWidth = this.hitStrokeWidth === 'auto'
208
- ? this.strokeWidth
209
- : this.hitStrokeWidth;
208
+
209
+ const effectiveStrokeWidth =
210
+ this.hitStrokeWidth === 'auto' ? this.strokeWidth : this.hitStrokeWidth;
210
211
  const halfWidth = Math.max(effectiveStrokeWidth / 2 + 2, 5);
211
-
212
+
212
213
  // Unit vector perpendicular to line
213
214
  const perpX = -deltaY / length;
214
215
  const perpY = deltaX / length;
215
-
216
+
216
217
  // Four corners of oriented rectangle
217
218
  return [
218
219
  new Point(this.x1 + perpX * halfWidth, this.y1 + perpY * halfWidth),
@@ -230,10 +231,11 @@ export class Line<
230
231
  return super.containsPoint(point);
231
232
  }
232
233
  const distance = this._distanceToLineSegment(point.x, point.y);
233
- const effectiveStrokeWidth = this.hitStrokeWidth === 'auto'
234
- ? this.strokeWidth
235
- : this.hitStrokeWidth || 1;
236
-
234
+ const effectiveStrokeWidth =
235
+ this.hitStrokeWidth === 'auto'
236
+ ? this.strokeWidth
237
+ : this.hitStrokeWidth || 1;
238
+
237
239
  const tolerance = Math.max(effectiveStrokeWidth / 2 + 2, 5);
238
240
  return distance <= tolerance;
239
241
  }
@@ -241,15 +243,18 @@ export class Line<
241
243
  }
242
244
 
243
245
  _distanceToLineSegment(px: number, py: number): number {
244
- const x1 = this.x1, y1 = this.y1, x2 = this.x2, y2 = this.y2;
245
-
246
+ const x1 = this.x1,
247
+ y1 = this.y1,
248
+ x2 = this.x2,
249
+ y2 = this.y2;
250
+
246
251
  const pd2 = (x1 - x2) * (x1 - x2) + (y1 - y2) * (y1 - y2);
247
252
  if (pd2 === 0) {
248
253
  return Math.sqrt((px - x1) * (px - x1) + (py - y1) * (py - y1));
249
254
  }
250
-
255
+
251
256
  const u = ((px - x1) * (x2 - x1) + (py - y1) * (y2 - y1)) / pd2;
252
-
257
+
253
258
  let closestX: number, closestY: number;
254
259
  if (u < 0) {
255
260
  closestX = x1;
@@ -261,15 +266,17 @@ export class Line<
261
266
  closestX = x1 + u * (x2 - x1);
262
267
  closestY = y1 + u * (y2 - y1);
263
268
  }
264
-
265
- return Math.sqrt((px - closestX) * (px - closestX) + (py - closestY) * (py - closestY));
269
+
270
+ return Math.sqrt(
271
+ (px - closestX) * (px - closestX) + (py - closestY) * (py - closestY),
272
+ );
266
273
  }
267
274
 
268
275
  _endpointActionHandler(
269
276
  eventData: TPointerEvent,
270
277
  transformData: Transform,
271
278
  x: number,
272
- y: number
279
+ y: number,
273
280
  ) {
274
281
  const controlKey = transformData.corner;
275
282
  const pointer = new Point(x, y);
@@ -293,6 +300,15 @@ export class Line<
293
300
  this.x2 = newX;
294
301
  this.y2 = newY;
295
302
  }
303
+
304
+ // Update gradient coordinates if stroke is a gradient (but not during SVG export)
305
+ if (this.stroke instanceof Gradient && !this._exportingSVG) {
306
+ this.stroke.coords.x1 = this.x1;
307
+ this.stroke.coords.y1 = this.y1;
308
+ this.stroke.coords.x2 = this.x2;
309
+ this.stroke.coords.y2 = this.y2;
310
+ }
311
+
296
312
  this.dirty = true;
297
313
  this.setCoords();
298
314
  this.canvas?.requestRenderAll();
@@ -312,7 +328,11 @@ export class Line<
312
328
  this.dirty = true;
313
329
  this._updatingEndpoints = false;
314
330
  this.canvas?.requestRenderAll();
315
- this.fire('modified', { transform: transformData, target: this, e: eventData });
331
+ this.fire('modified', {
332
+ transform: transformData,
333
+ target: this,
334
+ e: eventData,
335
+ });
316
336
  return true;
317
337
  }
318
338
 
@@ -320,7 +340,7 @@ export class Line<
320
340
  fromX: number,
321
341
  fromY: number,
322
342
  toX: number,
323
- toY: number
343
+ toY: number,
324
344
  ): { x: number; y: number } {
325
345
  const deltaX = toX - fromX;
326
346
  const deltaY = toY - fromY;
@@ -347,7 +367,7 @@ export class Line<
347
367
  this.setPositionByOrigin(
348
368
  new Point(left + width / 2, top + height / 2),
349
369
  CENTER,
350
- CENTER
370
+ CENTER,
351
371
  );
352
372
  }
353
373
  }
@@ -359,8 +379,20 @@ export class Line<
359
379
  if (coordProps.includes(key as keyof UniqueLineCoords)) {
360
380
  this._setWidthHeight();
361
381
  this.dirty = true;
382
+
383
+ // Update gradient coordinates if stroke is a gradient (but not during SVG export)
384
+ if (this.stroke instanceof Gradient && !this._exportingSVG) {
385
+ this.stroke.coords.x1 = this.x1;
386
+ this.stroke.coords.y1 = this.y1;
387
+ this.stroke.coords.x2 = this.x2;
388
+ this.stroke.coords.y2 = this.y2;
389
+ }
362
390
  }
363
- if ((key === 'left' || key === 'top') && this.canvas && !this._updatingEndpoints) {
391
+ if (
392
+ (key === 'left' || key === 'top') &&
393
+ this.canvas &&
394
+ !this._updatingEndpoints
395
+ ) {
364
396
  const deltaX = this.left - oldLeft;
365
397
  const deltaY = this.top - oldTop;
366
398
  if (deltaX !== 0 || deltaY !== 0) {
@@ -369,6 +401,15 @@ export class Line<
369
401
  this.y1 += deltaY;
370
402
  this.x2 += deltaX;
371
403
  this.y2 += deltaY;
404
+
405
+ // Update gradient coordinates if stroke is a gradient
406
+ if (this.stroke instanceof Gradient) {
407
+ this.stroke.coords.x1 = this.x1;
408
+ this.stroke.coords.y1 = this.y1;
409
+ this.stroke.coords.x2 = this.x2;
410
+ this.stroke.coords.y2 = this.y2;
411
+ }
412
+
372
413
  this._updatingEndpoints = false;
373
414
  }
374
415
  }
@@ -387,13 +428,21 @@ export class Line<
387
428
  if (!this.visible) return;
388
429
  ctx.save();
389
430
  ctx.globalAlpha = this.opacity;
390
- ctx.strokeStyle = this.stroke?.toString() || '#000';
391
431
  ctx.lineWidth = this.strokeWidth;
392
432
  ctx.lineCap = this.strokeLineCap || 'butt';
393
433
  ctx.beginPath();
394
434
  ctx.moveTo(this.x1, this.y1);
395
435
  ctx.lineTo(this.x2, this.y2);
436
+
437
+ const origStrokeStyle = ctx.strokeStyle;
438
+ if (isFiller(this.stroke)) {
439
+ ctx.strokeStyle = this.stroke.toLive(ctx)!;
440
+ } else {
441
+ ctx.strokeStyle = this.stroke?.toString() || '#000';
442
+ }
443
+
396
444
  ctx.stroke();
445
+ ctx.strokeStyle = origStrokeStyle;
397
446
  ctx.restore();
398
447
  }
399
448
 
@@ -416,9 +465,9 @@ export class Line<
416
465
  return new Point((this.x1 + this.x2) / 2, (this.y1 + this.y2) / 2);
417
466
  }
418
467
 
419
- toObject<
468
+ toObject<
420
469
  T extends Omit<Props & TClassProperties<this>, keyof SProps>,
421
- K extends keyof T = never
470
+ K extends keyof T = never,
422
471
  >(propertiesToInclude: K[] = []): Pick<T, K> & SProps {
423
472
  if (this._useEndpointCoords) {
424
473
  return {
@@ -469,8 +518,21 @@ export class Line<
469
518
  _toSVG() {
470
519
  if (this._useEndpointCoords) {
471
520
  // Use absolute coordinates to bypass all Fabric.js transforms
521
+ // Handle gradients manually for proper SVG export
522
+ let strokeAttr = '';
523
+ if (this.stroke instanceof Gradient) {
524
+ // Let Fabric.js handle gradient definition, but we'll use the reference
525
+ strokeAttr = `stroke="url(#${this.stroke.id})"`;
526
+ } else {
527
+ strokeAttr = `stroke="${this.stroke || 'none'}"`;
528
+ }
529
+
472
530
  return [
473
- `<line stroke="${this.stroke}" stroke-width="${this.strokeWidth}" stroke-linecap="${this.strokeLineCap}" `,
531
+ `<line ${strokeAttr} stroke-width="${this.strokeWidth}" stroke-linecap="${this.strokeLineCap}" `,
532
+ `stroke-dasharray="${this.strokeDashArray ? this.strokeDashArray.join(' ') : 'none'}" `,
533
+ `stroke-dashoffset="${this.strokeDashOffset}" stroke-linejoin="${this.strokeLineJoin}" `,
534
+ `stroke-miterlimit="${this.strokeMiterLimit}" fill="${this.fill || 'none'}" `,
535
+ `fill-rule="${this.fillRule}" opacity="${this.opacity}" `,
474
536
  `x1="${this.x1}" y1="${this.y1}" x2="${this.x2}" y2="${this.y2}" />\n`,
475
537
  ];
476
538
  } else {
@@ -486,9 +548,33 @@ export class Line<
486
548
 
487
549
  toSVG(reviver?: (markup: string) => string): string {
488
550
  if (this._useEndpointCoords) {
489
- // Override toSVG to prevent Fabric.js from adding transform wrapper
490
- const markup = this._toSVG().join('');
491
- return reviver ? reviver(markup) : markup;
551
+ // For endpoint coords, we need to bypass transforms but still allow gradients
552
+ // Let's temporarily disable transforms during SVG generation
553
+ const originalLeft = this.left;
554
+ const originalTop = this.top;
555
+
556
+ // Set position to center of line for gradient calculation
557
+ this.left = (this.x1 + this.x2) / 2;
558
+ this.top = (this.y1 + this.y2) / 2;
559
+
560
+ // Get the SVG with standard system (for gradient handling)
561
+ const standardSVG = super.toSVG(reviver);
562
+
563
+ // Restore original position
564
+ this.left = originalLeft;
565
+ this.top = originalTop;
566
+
567
+ // Extract gradient definition and clean up the line element
568
+ // Remove the transform wrapper and update coordinates
569
+ const cleanSVG = standardSVG
570
+ .replace(/<g transform="[^"]*"[^>]*>/g, '')
571
+ .replace(/<\/g>/g, '')
572
+ .replace(/x1="[^"]*"/g, `x1="${this.x1}"`)
573
+ .replace(/y1="[^"]*"/g, `y1="${this.y1}"`)
574
+ .replace(/x2="[^"]*"/g, `x2="${this.x2}"`)
575
+ .replace(/y2="[^"]*"/g, `y2="${this.y2}"`);
576
+
577
+ return cleanSVG;
492
578
  }
493
579
  // Use default behavior for legacy mode
494
580
  return super.toSVG(reviver);
@@ -499,7 +585,7 @@ export class Line<
499
585
  static async fromElement(
500
586
  element: HTMLElement,
501
587
  options?: Abortable,
502
- cssRules?: CSSRules
588
+ cssRules?: CSSRules,
503
589
  ) {
504
590
  const {
505
591
  x1 = 0,
@@ -511,7 +597,7 @@ export class Line<
511
597
  return new this([x1, y1, x2, y2], parsedAttributes);
512
598
  }
513
599
 
514
- static fromObject<T extends TOptions<SerializedLineProps>>({
600
+ static fromObject<T extends TOptions<SerializedLineProps>>({
515
601
  x1,
516
602
  y1,
517
603
  x2,
@@ -520,10 +606,10 @@ export class Line<
520
606
  }: T) {
521
607
  return this._fromObject<Line>(
522
608
  { ...object, points: [x1, y1, x2, y2] },
523
- { extraParam: 'points' }
609
+ { extraParam: 'points' },
524
610
  );
525
611
  }
526
612
  }
527
613
 
528
614
  classRegistry.setClass(Line);
529
- classRegistry.setSVGClass(Line);
615
+ classRegistry.setSVGClass(Line);