@nasser-sw/fabric 7.0.1-beta3 → 7.0.1-beta5
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/0 +0 -0
- package/dist/index.js +345 -162
- 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 +345 -162
- package/dist/index.mjs.map +1 -1
- package/dist/index.node.cjs +345 -162
- package/dist/index.node.cjs.map +1 -1
- package/dist/index.node.mjs +345 -162
- 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 +32 -86
- 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 +345 -161
- package/dist/src/shapes/Line.mjs.map +1 -1
- package/dist-extensions/src/shapes/CustomLine.d.ts +10 -0
- package/dist-extensions/src/shapes/CustomLine.d.ts.map +1 -0
- package/dist-extensions/src/shapes/Line.d.ts +32 -86
- package/dist-extensions/src/shapes/Line.d.ts.map +1 -1
- package/fabric-test-editor.html +157 -8
- package/fabric-test2.html +513 -0
- package/fabric.ts +182 -182
- package/package.json +1 -1
- package/src/shapes/Line.ts +397 -164
- package/debug/konva/CHANGELOG.md +0 -1474
- package/debug/konva/LICENSE +0 -22
- package/debug/konva/README.md +0 -205
- package/debug/konva/gulpfile.mjs +0 -110
- package/debug/konva/package.json +0 -139
- package/debug/konva/release.sh +0 -65
- package/debug/konva/resources/doc-includes/ContainerParams.txt +0 -6
- package/debug/konva/resources/doc-includes/NodeParams.txt +0 -20
- package/debug/konva/resources/doc-includes/ShapeParams.txt +0 -53
- package/debug/konva/resources/jsdoc.conf.json +0 -28
- package/debug/konva/rollup.config.mjs +0 -32
- package/debug/konva/src/Animation.ts +0 -237
- package/debug/konva/src/BezierFunctions.ts +0 -826
- package/debug/konva/src/Canvas.ts +0 -193
- package/debug/konva/src/Container.ts +0 -649
- package/debug/konva/src/Context.ts +0 -1017
- package/debug/konva/src/Core.ts +0 -5
- package/debug/konva/src/DragAndDrop.ts +0 -173
- package/debug/konva/src/Factory.ts +0 -246
- package/debug/konva/src/FastLayer.ts +0 -29
- package/debug/konva/src/Global.ts +0 -210
- package/debug/konva/src/Group.ts +0 -31
- package/debug/konva/src/Layer.ts +0 -546
- package/debug/konva/src/Node.ts +0 -3477
- package/debug/konva/src/PointerEvents.ts +0 -67
- package/debug/konva/src/Shape.ts +0 -2081
- package/debug/konva/src/Stage.ts +0 -1000
- package/debug/konva/src/Tween.ts +0 -811
- package/debug/konva/src/Util.ts +0 -1123
- package/debug/konva/src/Validators.ts +0 -210
- package/debug/konva/src/_CoreInternals.ts +0 -85
- package/debug/konva/src/_FullInternals.ts +0 -171
- package/debug/konva/src/canvas-backend.ts +0 -36
- package/debug/konva/src/filters/Blur.ts +0 -388
- package/debug/konva/src/filters/Brighten.ts +0 -48
- package/debug/konva/src/filters/Brightness.ts +0 -30
- package/debug/konva/src/filters/Contrast.ts +0 -75
- package/debug/konva/src/filters/Emboss.ts +0 -207
- package/debug/konva/src/filters/Enhance.ts +0 -154
- package/debug/konva/src/filters/Grayscale.ts +0 -25
- package/debug/konva/src/filters/HSL.ts +0 -108
- package/debug/konva/src/filters/HSV.ts +0 -106
- package/debug/konva/src/filters/Invert.ts +0 -23
- package/debug/konva/src/filters/Kaleidoscope.ts +0 -274
- package/debug/konva/src/filters/Mask.ts +0 -220
- package/debug/konva/src/filters/Noise.ts +0 -44
- package/debug/konva/src/filters/Pixelate.ts +0 -107
- package/debug/konva/src/filters/Posterize.ts +0 -46
- package/debug/konva/src/filters/RGB.ts +0 -82
- package/debug/konva/src/filters/RGBA.ts +0 -103
- package/debug/konva/src/filters/Sepia.ts +0 -27
- package/debug/konva/src/filters/Solarize.ts +0 -29
- package/debug/konva/src/filters/Threshold.ts +0 -44
- package/debug/konva/src/index.ts +0 -3
- package/debug/konva/src/shapes/Arc.ts +0 -176
- package/debug/konva/src/shapes/Arrow.ts +0 -231
- package/debug/konva/src/shapes/Circle.ts +0 -76
- package/debug/konva/src/shapes/Ellipse.ts +0 -121
- package/debug/konva/src/shapes/Image.ts +0 -319
- package/debug/konva/src/shapes/Label.ts +0 -386
- package/debug/konva/src/shapes/Line.ts +0 -364
- package/debug/konva/src/shapes/Path.ts +0 -1013
- package/debug/konva/src/shapes/Rect.ts +0 -79
- package/debug/konva/src/shapes/RegularPolygon.ts +0 -167
- package/debug/konva/src/shapes/Ring.ts +0 -94
- package/debug/konva/src/shapes/Sprite.ts +0 -370
- package/debug/konva/src/shapes/Star.ts +0 -125
- package/debug/konva/src/shapes/Text.ts +0 -1065
- package/debug/konva/src/shapes/TextPath.ts +0 -583
- package/debug/konva/src/shapes/Transformer.ts +0 -1889
- package/debug/konva/src/shapes/Wedge.ts +0 -129
- package/debug/konva/src/skia-backend.ts +0 -35
- package/debug/konva/src/types.ts +0 -84
- package/debug/konva/tsconfig.json +0 -31
- package/debug/konva/tsconfig.test.json +0 -7
package/dist/src/shapes/Line.mjs
CHANGED
|
@@ -14,35 +14,32 @@ 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';
|
|
17
18
|
import { cacheProperties } from './Object/defaultValues.mjs';
|
|
18
19
|
|
|
19
|
-
// @TODO this code is terrible and Line should be a special case of polyline.
|
|
20
|
-
|
|
21
20
|
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
21
|
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
22
|
constructor() {
|
|
37
|
-
let [x1, y1, x2, y2] = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : [0, 0,
|
|
23
|
+
let [x1, y1, x2, y2] = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : [0, 0, 100, 0];
|
|
38
24
|
let options = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
|
|
39
25
|
super();
|
|
40
|
-
|
|
26
|
+
_defineProperty(this, "hitStrokeWidth", 'auto');
|
|
27
|
+
_defineProperty(this, "_updatingEndpoints", false);
|
|
28
|
+
_defineProperty(this, "_useEndpointCoords", true);
|
|
41
29
|
this.setOptions(options);
|
|
42
30
|
this.x1 = x1;
|
|
43
31
|
this.x2 = x2;
|
|
44
32
|
this.y1 = y1;
|
|
45
33
|
this.y2 = y2;
|
|
34
|
+
if (options.hitStrokeWidth !== undefined) {
|
|
35
|
+
this.hitStrokeWidth = options.hitStrokeWidth;
|
|
36
|
+
}
|
|
37
|
+
this.hasBorders = false;
|
|
38
|
+
this.hasControls = true;
|
|
39
|
+
this.selectable = true;
|
|
40
|
+
this.hoverCursor = 'move';
|
|
41
|
+
this.perPixelTargetFind = false;
|
|
42
|
+
this.strokeLineCap = 'butt';
|
|
46
43
|
this._setWidthHeight();
|
|
47
44
|
const {
|
|
48
45
|
left,
|
|
@@ -50,96 +47,323 @@ class Line extends FabricObject {
|
|
|
50
47
|
} = options;
|
|
51
48
|
typeof left === 'number' && this.set(LEFT, left);
|
|
52
49
|
typeof top === 'number' && this.set(TOP, top);
|
|
50
|
+
this._setupLineControls();
|
|
51
|
+
}
|
|
52
|
+
_setupLineControls() {
|
|
53
|
+
this.controls = {
|
|
54
|
+
p1: new Control({
|
|
55
|
+
x: 0,
|
|
56
|
+
y: 0,
|
|
57
|
+
cursorStyle: 'move',
|
|
58
|
+
actionHandler: this._endpointActionHandler.bind(this),
|
|
59
|
+
positionHandler: this._p1PositionHandler.bind(this),
|
|
60
|
+
render: this._renderEndpointControl.bind(this),
|
|
61
|
+
sizeX: 12,
|
|
62
|
+
sizeY: 12
|
|
63
|
+
}),
|
|
64
|
+
p2: new Control({
|
|
65
|
+
x: 0,
|
|
66
|
+
y: 0,
|
|
67
|
+
cursorStyle: 'move',
|
|
68
|
+
actionHandler: this._endpointActionHandler.bind(this),
|
|
69
|
+
positionHandler: this._p2PositionHandler.bind(this),
|
|
70
|
+
render: this._renderEndpointControl.bind(this),
|
|
71
|
+
sizeX: 12,
|
|
72
|
+
sizeY: 12
|
|
73
|
+
})
|
|
74
|
+
};
|
|
75
|
+
}
|
|
76
|
+
_p1PositionHandler() {
|
|
77
|
+
var _this$canvas;
|
|
78
|
+
const vpt = ((_this$canvas = this.canvas) === null || _this$canvas === void 0 ? void 0 : _this$canvas.viewportTransform) || [1, 0, 0, 1, 0, 0];
|
|
79
|
+
return new Point(this.x1, this.y1).transform(vpt);
|
|
80
|
+
}
|
|
81
|
+
_p2PositionHandler() {
|
|
82
|
+
var _this$canvas2;
|
|
83
|
+
const vpt = ((_this$canvas2 = this.canvas) === null || _this$canvas2 === void 0 ? void 0 : _this$canvas2.viewportTransform) || [1, 0, 0, 1, 0, 0];
|
|
84
|
+
return new Point(this.x2, this.y2).transform(vpt);
|
|
85
|
+
}
|
|
86
|
+
_renderEndpointControl(ctx, left, top) {
|
|
87
|
+
const size = 12;
|
|
88
|
+
ctx.save();
|
|
89
|
+
ctx.fillStyle = '#007bff';
|
|
90
|
+
ctx.strokeStyle = '#ffffff';
|
|
91
|
+
ctx.lineWidth = 2;
|
|
92
|
+
ctx.beginPath();
|
|
93
|
+
ctx.arc(left, top, size / 2, 0, 2 * Math.PI);
|
|
94
|
+
ctx.fill();
|
|
95
|
+
ctx.stroke();
|
|
96
|
+
ctx.restore();
|
|
97
|
+
}
|
|
98
|
+
drawBorders(ctx) {
|
|
99
|
+
let styleOverride = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
|
|
100
|
+
if (this._useEndpointCoords) {
|
|
101
|
+
this._drawLineBorders(ctx, styleOverride);
|
|
102
|
+
return this;
|
|
103
|
+
}
|
|
104
|
+
return super.drawBorders(ctx, styleOverride, {});
|
|
105
|
+
}
|
|
106
|
+
_drawLineBorders(ctx) {
|
|
107
|
+
var _this$canvas3;
|
|
108
|
+
let styleOverride = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
|
|
109
|
+
const vpt = ((_this$canvas3 = this.canvas) === null || _this$canvas3 === void 0 ? void 0 : _this$canvas3.viewportTransform) || [1, 0, 0, 1, 0, 0];
|
|
110
|
+
ctx.save();
|
|
111
|
+
ctx.setTransform(vpt[0], vpt[1], vpt[2], vpt[3], vpt[4], vpt[5]);
|
|
112
|
+
ctx.strokeStyle = styleOverride.borderColor || this.borderColor || 'rgba(100, 200, 200, 0.5)';
|
|
113
|
+
ctx.lineWidth = (this.strokeWidth || 1) + 5;
|
|
114
|
+
ctx.lineCap = this.strokeLineCap || 'butt';
|
|
115
|
+
ctx.globalAlpha = this.isMoving ? this.borderOpacityWhenMoving : 1;
|
|
116
|
+
ctx.beginPath();
|
|
117
|
+
ctx.moveTo(this.x1, this.y1);
|
|
118
|
+
ctx.lineTo(this.x2, this.y2);
|
|
119
|
+
ctx.stroke();
|
|
120
|
+
ctx.restore();
|
|
121
|
+
}
|
|
122
|
+
_renderControls(ctx) {
|
|
123
|
+
let styleOverride = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
|
|
124
|
+
ctx.save();
|
|
125
|
+
ctx.globalAlpha = this.isMoving ? this.borderOpacityWhenMoving : 1;
|
|
126
|
+
this.drawControls(ctx, styleOverride);
|
|
127
|
+
ctx.restore();
|
|
128
|
+
}
|
|
129
|
+
getBoundingRect() {
|
|
130
|
+
if (this._useEndpointCoords) {
|
|
131
|
+
const {
|
|
132
|
+
x1,
|
|
133
|
+
y1,
|
|
134
|
+
x2,
|
|
135
|
+
y2
|
|
136
|
+
} = this;
|
|
137
|
+
const effectiveStrokeWidth = this.hitStrokeWidth === 'auto' ? this.strokeWidth : this.hitStrokeWidth;
|
|
138
|
+
const padding = Math.max(effectiveStrokeWidth / 2 + 5, 10);
|
|
139
|
+
return {
|
|
140
|
+
left: Math.min(x1, x2) - padding,
|
|
141
|
+
top: Math.min(y1, y2) - padding,
|
|
142
|
+
width: Math.abs(x2 - x1) + padding * 2 || padding * 2,
|
|
143
|
+
height: Math.abs(y2 - y1) + padding * 2 || padding * 2
|
|
144
|
+
};
|
|
145
|
+
}
|
|
146
|
+
return super.getBoundingRect();
|
|
53
147
|
}
|
|
148
|
+
setCoords() {
|
|
149
|
+
if (this._useEndpointCoords) {
|
|
150
|
+
// Set the object's center to the geometric center of the line
|
|
151
|
+
const center = this._findCenterFromElement();
|
|
152
|
+
this.left = center.x;
|
|
153
|
+
this.top = center.y;
|
|
54
154
|
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
155
|
+
// Set width and height for hit detection and bounding box
|
|
156
|
+
const effectiveStrokeWidth = this.hitStrokeWidth === 'auto' ? this.strokeWidth : this.hitStrokeWidth;
|
|
157
|
+
const hitPadding = Math.max(effectiveStrokeWidth / 2 + 5, 10);
|
|
158
|
+
this.width = Math.abs(this.x2 - this.x1) + hitPadding * 2;
|
|
159
|
+
this.height = Math.abs(this.y2 - this.y1) + hitPadding * 2;
|
|
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$canvas4;
|
|
186
|
+
if (((_this$canvas4 = this.canvas) === null || _this$canvas4 === void 0 ? void 0 : _this$canvas4.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$canvas6;
|
|
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$canvas5;
|
|
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
|
+
}
|
|
242
|
+
this.dirty = true;
|
|
243
|
+
this.setCoords();
|
|
244
|
+
(_this$canvas5 = this.canvas) === null || _this$canvas5 === void 0 || _this$canvas5.requestRenderAll();
|
|
245
|
+
return true;
|
|
246
|
+
}
|
|
83
247
|
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
248
|
+
// Fallback for old system
|
|
249
|
+
this._updatingEndpoints = true;
|
|
250
|
+
if (controlKey === 'p1') {
|
|
251
|
+
this.x1 = newX;
|
|
252
|
+
this.y1 = newY;
|
|
253
|
+
} else if (controlKey === 'p2') {
|
|
254
|
+
this.x2 = newX;
|
|
255
|
+
this.y2 = newY;
|
|
256
|
+
}
|
|
257
|
+
this._setWidthHeight();
|
|
258
|
+
this.dirty = true;
|
|
259
|
+
this._updatingEndpoints = false;
|
|
260
|
+
(_this$canvas6 = this.canvas) === null || _this$canvas6 === void 0 || _this$canvas6.requestRenderAll();
|
|
261
|
+
this.fire('modified', {
|
|
262
|
+
transform: transformData,
|
|
263
|
+
target: this,
|
|
264
|
+
e: eventData
|
|
265
|
+
});
|
|
266
|
+
return true;
|
|
267
|
+
}
|
|
268
|
+
_snapToAngle(fromX, fromY, toX, toY) {
|
|
269
|
+
const deltaX = toX - fromX;
|
|
270
|
+
const deltaY = toY - fromY;
|
|
271
|
+
const distance = Math.sqrt(deltaX * deltaX + deltaY * deltaY);
|
|
272
|
+
if (distance === 0) return {
|
|
273
|
+
x: toX,
|
|
274
|
+
y: toY
|
|
275
|
+
};
|
|
276
|
+
let angle = Math.atan2(deltaY, deltaX) * (180 / Math.PI);
|
|
277
|
+
const snapIncrement = 15;
|
|
278
|
+
const snappedAngle = Math.round(angle / snapIncrement) * snapIncrement;
|
|
279
|
+
const snappedRadians = snappedAngle * (Math.PI / 180);
|
|
280
|
+
return {
|
|
281
|
+
x: fromX + Math.cos(snappedRadians) * distance,
|
|
282
|
+
y: fromY + Math.sin(snappedRadians) * distance
|
|
283
|
+
};
|
|
284
|
+
}
|
|
285
|
+
_setWidthHeight() {
|
|
286
|
+
let skipReposition = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : false;
|
|
287
|
+
this.width = Math.abs(this.x2 - this.x1) || 1;
|
|
288
|
+
this.height = Math.abs(this.y2 - this.y1) || 1;
|
|
289
|
+
if (!skipReposition && !this._updatingEndpoints) {
|
|
290
|
+
const {
|
|
291
|
+
left,
|
|
292
|
+
top,
|
|
293
|
+
width,
|
|
294
|
+
height
|
|
295
|
+
} = makeBoundingBoxFromPoints([{
|
|
296
|
+
x: this.x1,
|
|
297
|
+
y: this.y1
|
|
298
|
+
}, {
|
|
299
|
+
x: this.x2,
|
|
300
|
+
y: this.y2
|
|
301
|
+
}]);
|
|
302
|
+
this.setPositionByOrigin(new Point(left + width / 2, top + height / 2), CENTER, CENTER);
|
|
303
|
+
}
|
|
304
|
+
}
|
|
89
305
|
_set(key, value) {
|
|
306
|
+
const oldLeft = this.left;
|
|
307
|
+
const oldTop = this.top;
|
|
90
308
|
super._set(key, value);
|
|
91
309
|
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
310
|
this._setWidthHeight();
|
|
311
|
+
this.dirty = true;
|
|
312
|
+
}
|
|
313
|
+
if ((key === 'left' || key === 'top') && this.canvas && !this._updatingEndpoints) {
|
|
314
|
+
const deltaX = this.left - oldLeft;
|
|
315
|
+
const deltaY = this.top - oldTop;
|
|
316
|
+
if (deltaX !== 0 || deltaY !== 0) {
|
|
317
|
+
this._updatingEndpoints = true;
|
|
318
|
+
this.x1 += deltaX;
|
|
319
|
+
this.y1 += deltaY;
|
|
320
|
+
this.x2 += deltaX;
|
|
321
|
+
this.y2 += deltaY;
|
|
322
|
+
this._updatingEndpoints = false;
|
|
323
|
+
}
|
|
99
324
|
}
|
|
100
325
|
return this;
|
|
101
326
|
}
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
327
|
+
render(ctx) {
|
|
328
|
+
if (this._useEndpointCoords) {
|
|
329
|
+
this._renderDirectly(ctx);
|
|
330
|
+
return;
|
|
331
|
+
}
|
|
332
|
+
super.render(ctx);
|
|
333
|
+
}
|
|
334
|
+
_renderDirectly(ctx) {
|
|
335
|
+
var _this$canvas7, _this$stroke;
|
|
336
|
+
if (!this.visible) return;
|
|
337
|
+
ctx.save();
|
|
338
|
+
const vpt = ((_this$canvas7 = this.canvas) === null || _this$canvas7 === void 0 ? void 0 : _this$canvas7.viewportTransform) || [1, 0, 0, 1, 0, 0];
|
|
339
|
+
ctx.transform(vpt[0], vpt[1], vpt[2], vpt[3], vpt[4], vpt[5]);
|
|
340
|
+
ctx.globalAlpha = this.opacity;
|
|
341
|
+
ctx.strokeStyle = ((_this$stroke = this.stroke) === null || _this$stroke === void 0 ? void 0 : _this$stroke.toString()) || '#000';
|
|
342
|
+
ctx.lineWidth = this.strokeWidth;
|
|
343
|
+
ctx.lineCap = this.strokeLineCap || 'butt';
|
|
344
|
+
ctx.beginPath();
|
|
345
|
+
ctx.moveTo(this.x1, this.y1);
|
|
346
|
+
ctx.lineTo(this.x2, this.y2);
|
|
347
|
+
ctx.stroke();
|
|
348
|
+
ctx.restore();
|
|
349
|
+
}
|
|
107
350
|
_render(ctx) {
|
|
351
|
+
if (this._useEndpointCoords) return;
|
|
108
352
|
ctx.beginPath();
|
|
109
353
|
const p = this.calcLinePoints();
|
|
110
354
|
ctx.moveTo(p.x1, p.y1);
|
|
111
355
|
ctx.lineTo(p.x2, p.y2);
|
|
112
356
|
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
357
|
const origStrokeStyle = ctx.strokeStyle;
|
|
118
358
|
if (isFiller(this.stroke)) {
|
|
119
359
|
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
360
|
}
|
|
124
361
|
this.stroke && this._renderStroke(ctx);
|
|
125
362
|
ctx.strokeStyle = origStrokeStyle;
|
|
126
363
|
}
|
|
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
364
|
_findCenterFromElement() {
|
|
135
365
|
return new Point((this.x1 + this.x2) / 2, (this.y1 + this.y2) / 2);
|
|
136
366
|
}
|
|
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
367
|
toObject() {
|
|
144
368
|
let propertiesToInclude = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : [];
|
|
145
369
|
return {
|
|
@@ -147,32 +371,25 @@ class Line extends FabricObject {
|
|
|
147
371
|
...this.calcLinePoints()
|
|
148
372
|
};
|
|
149
373
|
}
|
|
150
|
-
|
|
151
|
-
/*
|
|
152
|
-
* Calculate object dimensions from its properties
|
|
153
|
-
* @private
|
|
154
|
-
*/
|
|
155
374
|
_getNonTransformedDimensions() {
|
|
156
375
|
const dim = super._getNonTransformedDimensions();
|
|
157
|
-
if (this.strokeLineCap === '
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
}
|
|
161
|
-
if (this.height === 0) {
|
|
162
|
-
dim.x -= this.strokeWidth;
|
|
163
|
-
}
|
|
376
|
+
if (this.strokeLineCap === 'round') {
|
|
377
|
+
dim.x += this.strokeWidth;
|
|
378
|
+
dim.y += this.strokeWidth;
|
|
164
379
|
}
|
|
165
380
|
return dim;
|
|
166
381
|
}
|
|
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
382
|
calcLinePoints() {
|
|
383
|
+
if (this._updatingEndpoints) {
|
|
384
|
+
const centerX = (this.x1 + this.x2) / 2;
|
|
385
|
+
const centerY = (this.y1 + this.y2) / 2;
|
|
386
|
+
return {
|
|
387
|
+
x1: this.x1 - centerX,
|
|
388
|
+
y1: this.y1 - centerY,
|
|
389
|
+
x2: this.x2 - centerX,
|
|
390
|
+
y2: this.y2 - centerY
|
|
391
|
+
};
|
|
392
|
+
}
|
|
176
393
|
const {
|
|
177
394
|
x1: _x1,
|
|
178
395
|
x2: _x2,
|
|
@@ -181,48 +398,39 @@ class Line extends FabricObject {
|
|
|
181
398
|
width,
|
|
182
399
|
height
|
|
183
400
|
} = this;
|
|
184
|
-
const xMult = _x1 <= _x2 ? -1 : 1
|
|
185
|
-
|
|
186
|
-
x1 = xMult * width / 2,
|
|
187
|
-
y1 = yMult * height / 2,
|
|
188
|
-
x2 = xMult * -width / 2,
|
|
189
|
-
y2 = yMult * -height / 2;
|
|
401
|
+
const xMult = _x1 <= _x2 ? -1 : 1;
|
|
402
|
+
const yMult = _y1 <= _y2 ? -1 : 1;
|
|
190
403
|
return {
|
|
191
|
-
x1,
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
y2
|
|
404
|
+
x1: xMult * width / 2,
|
|
405
|
+
y1: yMult * height / 2,
|
|
406
|
+
x2: xMult * -width / 2,
|
|
407
|
+
y2: yMult * -height / 2
|
|
195
408
|
};
|
|
196
409
|
}
|
|
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
410
|
_toSVG() {
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
x2
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
411
|
+
if (this._useEndpointCoords) {
|
|
412
|
+
// Use absolute coordinates to bypass all Fabric.js transforms
|
|
413
|
+
return [`<line stroke="${this.stroke}" stroke-width="${this.strokeWidth}" stroke-linecap="${this.strokeLineCap}" `, `x1="${this.x1}" y1="${this.y1}" x2="${this.x2}" y2="${this.y2}" />\n`];
|
|
414
|
+
} else {
|
|
415
|
+
// Use standard calcLinePoints for legacy mode
|
|
416
|
+
const {
|
|
417
|
+
x1,
|
|
418
|
+
x2,
|
|
419
|
+
y1,
|
|
420
|
+
y2
|
|
421
|
+
} = this.calcLinePoints();
|
|
422
|
+
return ['<line ', 'COMMON_PARTS', `x1="${x1}" y1="${y1}" x2="${x2}" y2="${y2}" />\n`];
|
|
423
|
+
}
|
|
424
|
+
}
|
|
425
|
+
toSVG(reviver) {
|
|
426
|
+
if (this._useEndpointCoords) {
|
|
427
|
+
// Override toSVG to prevent Fabric.js from adding transform wrapper
|
|
428
|
+
const markup = this._toSVG().join('');
|
|
429
|
+
return reviver ? reviver(markup) : markup;
|
|
430
|
+
}
|
|
431
|
+
// Use default behavior for legacy mode
|
|
432
|
+
return super.toSVG(reviver);
|
|
213
433
|
}
|
|
214
|
-
|
|
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
|
-
*/
|
|
219
|
-
|
|
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
|
-
*/
|
|
226
434
|
static async fromElement(element, options, cssRules) {
|
|
227
435
|
const {
|
|
228
436
|
x1 = 0,
|
|
@@ -233,14 +441,6 @@ class Line extends FabricObject {
|
|
|
233
441
|
} = parseAttributes(element, this.ATTRIBUTE_NAMES, cssRules);
|
|
234
442
|
return new this([x1, y1, x2, y2], parsedAttributes);
|
|
235
443
|
}
|
|
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
444
|
static fromObject(_ref) {
|
|
245
445
|
let {
|
|
246
446
|
x1,
|
|
@@ -257,22 +457,6 @@ class Line extends FabricObject {
|
|
|
257
457
|
});
|
|
258
458
|
}
|
|
259
459
|
}
|
|
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
460
|
_defineProperty(Line, "type", 'Line');
|
|
277
461
|
_defineProperty(Line, "cacheProperties", [...cacheProperties, ...coordProps]);
|
|
278
462
|
_defineProperty(Line, "ATTRIBUTE_NAMES", SHARED_ATTRIBUTES.concat(coordProps));
|