@nasser-sw/fabric 7.0.1-beta7 → 7.0.1-beta8
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.
- package/dist/index.js +63 -7
- package/dist/index.js.map +1 -1
- package/dist/index.min.js +1 -1
- package/dist/index.min.js.map +1 -1
- package/dist/index.min.mjs +1 -1
- package/dist/index.min.mjs.map +1 -1
- package/dist/index.mjs +63 -7
- package/dist/index.mjs.map +1 -1
- package/dist/index.node.cjs +63 -7
- package/dist/index.node.cjs.map +1 -1
- package/dist/index.node.mjs +63 -7
- package/dist/index.node.mjs.map +1 -1
- package/dist/package.json.min.mjs +1 -1
- package/dist/package.json.mjs +1 -1
- package/dist/src/shapes/Line.d.ts +1 -0
- package/dist/src/shapes/Line.d.ts.map +1 -1
- package/dist/src/shapes/Line.min.mjs +1 -1
- package/dist/src/shapes/Line.min.mjs.map +1 -1
- package/dist/src/shapes/Line.mjs +63 -6
- package/dist/src/shapes/Line.mjs.map +1 -1
- package/dist-extensions/src/shapes/Line.d.ts +1 -0
- package/dist-extensions/src/shapes/Line.d.ts.map +1 -1
- package/fabric-test2.html +43 -0
- package/package.json +1 -1
- package/src/shapes/Line.ts +132 -46
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Line.d.ts","sourceRoot":"","sources":["../../../src/shapes/Line.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,SAAS,EAAE,gBAAgB,EAAE,QAAQ,EAAE,MAAM,aAAa,CAAC;AAEzE,OAAO,EAAE,YAAY,EAAmB,MAAM,uBAAuB,CAAC;AACtE,OAAO,EAAE,KAAK,EAAE,MAAM,UAAU,CAAC;AAEjC,OAAO,KAAK,EAAE,iBAAiB,EAAE,qBAAqB,EAAE,MAAM,gBAAgB,CAAC;AAC/E,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,kBAAkB,CAAC;AAGrD,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,oBAAoB,CAAC;AAEnD,OAAO,KAAK,EAAE,aAAa,EAAE,SAAS,EAAE,MAAM,kBAAkB,CAAC;AAKjE,UAAU,gBAAgB;IACxB,EAAE,EAAE,MAAM,CAAC;IACX,EAAE,EAAE,MAAM,CAAC;IACX,EAAE,EAAE,MAAM,CAAC;IACX,EAAE,EAAE,MAAM,CAAC;CACZ;AAED,MAAM,WAAW,mBACf,SAAQ,qBAAqB,EAC3B,gBAAgB;CAAG;AAEvB,qBAAa,IAAI,CACb,KAAK,SAAS,QAAQ,CAAC,iBAAiB,CAAC,GAAG,OAAO,CAAC,iBAAiB,CAAC,EACtE,MAAM,SAAS,mBAAmB,GAAG,mBAAmB,EACxD,SAAS,SAAS,YAAY,GAAG,YAAY,CAE/C,SAAQ,YAAY,CAAC,KAAK,EAAE,MAAM,EAAE,SAAS,CAC7C,YAAW,gBAAgB;IAEnB,EAAE,EAAE,MAAM,CAAC;IACX,EAAE,EAAE,MAAM,CAAC;IACX,EAAE,EAAE,MAAM,CAAC;IACX,EAAE,EAAE,MAAM,CAAC;IAEnB,cAAc,EAAE,MAAM,GAAG,MAAM,CAAU;IAEzC,OAAO,CAAC,kBAAkB,CAAS;IACnC,OAAO,CAAC,kBAAkB,CAAQ;
|
|
1
|
+
{"version":3,"file":"Line.d.ts","sourceRoot":"","sources":["../../../src/shapes/Line.ts"],"names":[],"mappings":"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"}
|
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();
|
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-
|
|
5
|
+
"version": "7.0.1-beta8",
|
|
6
6
|
"author": "Juriy Zaytsev <kangax@gmail.com>",
|
|
7
7
|
"contributors": [
|
|
8
8
|
{
|
package/src/shapes/Line.ts
CHANGED
|
@@ -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 {
|
|
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(
|
|
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 ||
|
|
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 =
|
|
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 =
|
|
234
|
-
|
|
235
|
-
|
|
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,
|
|
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(
|
|
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', {
|
|
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 (
|
|
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
|
|
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
|
-
//
|
|
490
|
-
|
|
491
|
-
|
|
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);
|