fabric-rails 1.0.12 → 1.0.12.1
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.
- data/CHANGELOG.md +16 -0
- data/README.md +1 -1
- data/lib/fabric/rails/version.rb +2 -2
- data/vendor/assets/javascripts/event.js +1909 -0
- data/vendor/assets/javascripts/fabric.js +64 -16464
- data/vendor/assets/javascripts/fabric/HEADER.js +31 -0
- data/vendor/assets/javascripts/fabric/canvas.class.js +1007 -0
- data/vendor/assets/javascripts/fabric/canvas_animation.mixin.js +113 -0
- data/vendor/assets/javascripts/fabric/canvas_events.mixin.js +482 -0
- data/vendor/assets/javascripts/fabric/canvas_gestures.mixin.js +79 -0
- data/vendor/assets/javascripts/fabric/canvas_serialization.mixin.js +311 -0
- data/vendor/assets/javascripts/fabric/circle.class.js +182 -0
- data/vendor/assets/javascripts/fabric/color.class.js +284 -0
- data/vendor/assets/javascripts/fabric/ellipse.class.js +169 -0
- data/vendor/assets/javascripts/fabric/freedrawing.class.js +256 -0
- data/vendor/assets/javascripts/fabric/gradient.class.js +211 -0
- data/vendor/assets/javascripts/fabric/group.class.js +556 -0
- data/vendor/assets/javascripts/fabric/image.class.js +418 -0
- data/vendor/assets/javascripts/fabric/image_filters.js +809 -0
- data/vendor/assets/javascripts/fabric/intersection.class.js +178 -0
- data/vendor/assets/javascripts/fabric/line.class.js +188 -0
- data/vendor/assets/javascripts/fabric/log.js +26 -0
- data/vendor/assets/javascripts/fabric/node.js +149 -0
- data/vendor/assets/javascripts/fabric/object.class.js +1068 -0
- data/vendor/assets/javascripts/fabric/object_geometry.mixin.js +308 -0
- data/vendor/assets/javascripts/fabric/object_interactivity.mixin.js +496 -0
- data/vendor/assets/javascripts/fabric/object_origin.mixin.js +207 -0
- data/vendor/assets/javascripts/fabric/object_straightening.mixin.js +94 -0
- data/vendor/assets/javascripts/fabric/observable.mixin.js +91 -0
- data/vendor/assets/javascripts/fabric/parser.js +750 -0
- data/vendor/assets/javascripts/fabric/path.class.js +794 -0
- data/vendor/assets/javascripts/fabric/path_group.class.js +240 -0
- data/vendor/assets/javascripts/fabric/pattern.class.js +69 -0
- data/vendor/assets/javascripts/fabric/point.class.js +327 -0
- data/vendor/assets/javascripts/fabric/polygon.class.js +184 -0
- data/vendor/assets/javascripts/fabric/polyline.class.js +157 -0
- data/vendor/assets/javascripts/fabric/rect.class.js +298 -0
- data/vendor/assets/javascripts/fabric/scout.js +45 -0
- data/vendor/assets/javascripts/fabric/shadow.class.js +70 -0
- data/vendor/assets/javascripts/fabric/stateful.js +88 -0
- data/vendor/assets/javascripts/fabric/static_canvas.class.js +1298 -0
- data/vendor/assets/javascripts/fabric/text.class.js +934 -0
- data/vendor/assets/javascripts/fabric/triangle.class.js +108 -0
- data/vendor/assets/javascripts/fabric/util/anim_ease.js +360 -0
- data/vendor/assets/javascripts/fabric/util/dom_event.js +237 -0
- data/vendor/assets/javascripts/fabric/util/dom_misc.js +245 -0
- data/vendor/assets/javascripts/fabric/util/dom_request.js +72 -0
- data/vendor/assets/javascripts/fabric/util/dom_style.js +71 -0
- data/vendor/assets/javascripts/fabric/util/lang_array.js +250 -0
- data/vendor/assets/javascripts/fabric/util/lang_class.js +97 -0
- data/vendor/assets/javascripts/fabric/util/lang_function.js +35 -0
- data/vendor/assets/javascripts/fabric/util/lang_object.js +34 -0
- data/vendor/assets/javascripts/fabric/util/lang_string.js +60 -0
- data/vendor/assets/javascripts/fabric/util/misc.js +406 -0
- data/vendor/assets/javascripts/json2.js +491 -0
- metadata +53 -2
@@ -0,0 +1,308 @@
|
|
1
|
+
(function() {
|
2
|
+
|
3
|
+
var degreesToRadians = fabric.util.degreesToRadians;
|
4
|
+
|
5
|
+
fabric.util.object.extend(fabric.Object.prototype, /** @scope fabric.Object.prototype */ {
|
6
|
+
|
7
|
+
/**
|
8
|
+
* Returns true if object intersects with an area formed by 2 points
|
9
|
+
* @method intersectsWithRect
|
10
|
+
* @param {Object} selectionTL
|
11
|
+
* @param {Object} selectionBR
|
12
|
+
* @return {Boolean}
|
13
|
+
*/
|
14
|
+
intersectsWithRect: function(selectionTL, selectionBR) {
|
15
|
+
var oCoords = this.oCoords,
|
16
|
+
tl = new fabric.Point(oCoords.tl.x, oCoords.tl.y),
|
17
|
+
tr = new fabric.Point(oCoords.tr.x, oCoords.tr.y),
|
18
|
+
bl = new fabric.Point(oCoords.bl.x, oCoords.bl.y),
|
19
|
+
br = new fabric.Point(oCoords.br.x, oCoords.br.y);
|
20
|
+
|
21
|
+
var intersection = fabric.Intersection.intersectPolygonRectangle(
|
22
|
+
[tl, tr, br, bl],
|
23
|
+
selectionTL,
|
24
|
+
selectionBR
|
25
|
+
);
|
26
|
+
return intersection.status === 'Intersection';
|
27
|
+
},
|
28
|
+
|
29
|
+
/**
|
30
|
+
* Returns true if object intersects with another object
|
31
|
+
* @method intersectsWithObject
|
32
|
+
* @param {Object} other Object to test
|
33
|
+
* @return {Boolean}
|
34
|
+
*/
|
35
|
+
intersectsWithObject: function(other) {
|
36
|
+
// extracts coords
|
37
|
+
function getCoords(oCoords) {
|
38
|
+
return {
|
39
|
+
tl: new fabric.Point(oCoords.tl.x, oCoords.tl.y),
|
40
|
+
tr: new fabric.Point(oCoords.tr.x, oCoords.tr.y),
|
41
|
+
bl: new fabric.Point(oCoords.bl.x, oCoords.bl.y),
|
42
|
+
br: new fabric.Point(oCoords.br.x, oCoords.br.y)
|
43
|
+
};
|
44
|
+
}
|
45
|
+
var thisCoords = getCoords(this.oCoords),
|
46
|
+
otherCoords = getCoords(other.oCoords);
|
47
|
+
|
48
|
+
var intersection = fabric.Intersection.intersectPolygonPolygon(
|
49
|
+
[thisCoords.tl, thisCoords.tr, thisCoords.br, thisCoords.bl],
|
50
|
+
[otherCoords.tl, otherCoords.tr, otherCoords.br, otherCoords.bl]
|
51
|
+
);
|
52
|
+
|
53
|
+
return intersection.status === 'Intersection';
|
54
|
+
},
|
55
|
+
|
56
|
+
/**
|
57
|
+
* Returns true if object is fully contained within area of another object
|
58
|
+
* @method isContainedWithinObject
|
59
|
+
* @param {Object} other Object to test
|
60
|
+
* @return {Boolean}
|
61
|
+
*/
|
62
|
+
isContainedWithinObject: function(other) {
|
63
|
+
return this.isContainedWithinRect(other.oCoords.tl, other.oCoords.br);
|
64
|
+
},
|
65
|
+
|
66
|
+
/**
|
67
|
+
* Returns true if object is fully contained within area formed by 2 points
|
68
|
+
* @method isContainedWithinRect
|
69
|
+
* @param {Object} selectionTL
|
70
|
+
* @param {Object} selectionBR
|
71
|
+
* @return {Boolean}
|
72
|
+
*/
|
73
|
+
isContainedWithinRect: function(selectionTL, selectionBR) {
|
74
|
+
var oCoords = this.oCoords,
|
75
|
+
tl = new fabric.Point(oCoords.tl.x, oCoords.tl.y),
|
76
|
+
tr = new fabric.Point(oCoords.tr.x, oCoords.tr.y),
|
77
|
+
bl = new fabric.Point(oCoords.bl.x, oCoords.bl.y);
|
78
|
+
|
79
|
+
return tl.x > selectionTL.x
|
80
|
+
&& tr.x < selectionBR.x
|
81
|
+
&& tl.y > selectionTL.y
|
82
|
+
&& bl.y < selectionBR.y;
|
83
|
+
},
|
84
|
+
|
85
|
+
/**
|
86
|
+
* Returns width of an object's bounding rectangle
|
87
|
+
* @deprecated since 1.0.4
|
88
|
+
* @method getBoundingRectWidth
|
89
|
+
* @return {Number} width value
|
90
|
+
*/
|
91
|
+
getBoundingRectWidth: function() {
|
92
|
+
return this.getBoundingRect().width;
|
93
|
+
},
|
94
|
+
|
95
|
+
/**
|
96
|
+
* Returns height of an object's bounding rectangle
|
97
|
+
* @deprecated since 1.0.4
|
98
|
+
* @method getBoundingRectHeight
|
99
|
+
* @return {Number} height value
|
100
|
+
*/
|
101
|
+
getBoundingRectHeight: function() {
|
102
|
+
return this.getBoundingRect().height;
|
103
|
+
},
|
104
|
+
|
105
|
+
/**
|
106
|
+
* Returns coordinates of object's bounding rectangle (left, top, width, height)
|
107
|
+
* @method getBoundingRect
|
108
|
+
* @return {Object} Object with left, top, width, height properties
|
109
|
+
*/
|
110
|
+
getBoundingRect: function() {
|
111
|
+
this.oCoords || this.setCoords();
|
112
|
+
|
113
|
+
var xCoords = [this.oCoords.tl.x, this.oCoords.tr.x, this.oCoords.br.x, this.oCoords.bl.x];
|
114
|
+
var minX = fabric.util.array.min(xCoords);
|
115
|
+
var maxX = fabric.util.array.max(xCoords);
|
116
|
+
var width = Math.abs(minX - maxX);
|
117
|
+
|
118
|
+
var yCoords = [this.oCoords.tl.y, this.oCoords.tr.y, this.oCoords.br.y, this.oCoords.bl.y];
|
119
|
+
var minY = fabric.util.array.min(yCoords);
|
120
|
+
var maxY = fabric.util.array.max(yCoords);
|
121
|
+
var height = Math.abs(minY - maxY);
|
122
|
+
|
123
|
+
return {
|
124
|
+
left: minX,
|
125
|
+
top: minY,
|
126
|
+
width: width,
|
127
|
+
height: height
|
128
|
+
};
|
129
|
+
},
|
130
|
+
|
131
|
+
/**
|
132
|
+
* Returns width of an object
|
133
|
+
* @method getWidth
|
134
|
+
* @return {Number} width value
|
135
|
+
*/
|
136
|
+
getWidth: function() {
|
137
|
+
return this.width * this.scaleX;
|
138
|
+
},
|
139
|
+
|
140
|
+
/**
|
141
|
+
* Returns height of an object
|
142
|
+
* @method getHeight
|
143
|
+
* @return {Number} height value
|
144
|
+
*/
|
145
|
+
getHeight: function() {
|
146
|
+
return this.height * this.scaleY;
|
147
|
+
},
|
148
|
+
|
149
|
+
/**
|
150
|
+
* Makes sure the scale is valid and modifies it if necessary
|
151
|
+
* @private
|
152
|
+
* @method _constrainScale
|
153
|
+
* @param {Number} value
|
154
|
+
* @return {Number}
|
155
|
+
*/
|
156
|
+
_constrainScale: function(value) {
|
157
|
+
if (Math.abs(value) < this.minScaleLimit) {
|
158
|
+
if (value < 0)
|
159
|
+
return -this.minScaleLimit;
|
160
|
+
else
|
161
|
+
return this.minScaleLimit;
|
162
|
+
}
|
163
|
+
|
164
|
+
return value;
|
165
|
+
},
|
166
|
+
|
167
|
+
/**
|
168
|
+
* Scales an object (equally by x and y)
|
169
|
+
* @method scale
|
170
|
+
* @param value {Number} scale factor
|
171
|
+
* @return {fabric.Object} thisArg
|
172
|
+
* @chainable
|
173
|
+
*/
|
174
|
+
scale: function(value) {
|
175
|
+
value = this._constrainScale(value);
|
176
|
+
|
177
|
+
if (value < 0) {
|
178
|
+
this.flipX = !this.flipX;
|
179
|
+
this.flipY = !this.flipY;
|
180
|
+
value *= -1;
|
181
|
+
}
|
182
|
+
|
183
|
+
this.scaleX = value;
|
184
|
+
this.scaleY = value;
|
185
|
+
this.setCoords();
|
186
|
+
return this;
|
187
|
+
},
|
188
|
+
|
189
|
+
/**
|
190
|
+
* Scales an object to a given width, with respect to bounding box (scaling by x/y equally)
|
191
|
+
* @method scaleToWidth
|
192
|
+
* @param value {Number} new width value
|
193
|
+
* @return {fabric.Object} thisArg
|
194
|
+
* @chainable
|
195
|
+
*/
|
196
|
+
scaleToWidth: function(value) {
|
197
|
+
// adjust to bounding rect factor so that rotated shapes would fit as well
|
198
|
+
var boundingRectFactor = this.getBoundingRectWidth() / this.getWidth();
|
199
|
+
return this.scale(value / this.width / boundingRectFactor);
|
200
|
+
},
|
201
|
+
|
202
|
+
/**
|
203
|
+
* Scales an object to a given height, with respect to bounding box (scaling by x/y equally)
|
204
|
+
* @method scaleToHeight
|
205
|
+
* @param value {Number} new height value
|
206
|
+
* @return {fabric.Object} thisArg
|
207
|
+
* @chainable
|
208
|
+
*/
|
209
|
+
scaleToHeight: function(value) {
|
210
|
+
// adjust to bounding rect factor so that rotated shapes would fit as well
|
211
|
+
var boundingRectFactor = this.getBoundingRectHeight() / this.getHeight();
|
212
|
+
return this.scale(value / this.height / boundingRectFactor);
|
213
|
+
},
|
214
|
+
|
215
|
+
/**
|
216
|
+
* Sets corner position coordinates based on current angle, width and height
|
217
|
+
* @method setCoords
|
218
|
+
* @return {fabric.Object} thisArg
|
219
|
+
* @chainable
|
220
|
+
*/
|
221
|
+
setCoords: function() {
|
222
|
+
|
223
|
+
var strokeWidth = this.strokeWidth > 1 ? this.strokeWidth : 0,
|
224
|
+
padding = this.padding,
|
225
|
+
theta = degreesToRadians(this.angle);
|
226
|
+
|
227
|
+
this.currentWidth = (this.width + strokeWidth) * this.scaleX + padding * 2;
|
228
|
+
this.currentHeight = (this.height + strokeWidth) * this.scaleY + padding * 2;
|
229
|
+
|
230
|
+
// If width is negative, make postive. Fixes path selection issue
|
231
|
+
if (this.currentWidth < 0) {
|
232
|
+
this.currentWidth = Math.abs(this.currentWidth);
|
233
|
+
}
|
234
|
+
|
235
|
+
var _hypotenuse = Math.sqrt(
|
236
|
+
Math.pow(this.currentWidth / 2, 2) +
|
237
|
+
Math.pow(this.currentHeight / 2, 2));
|
238
|
+
|
239
|
+
var _angle = Math.atan(this.currentHeight / this.currentWidth);
|
240
|
+
|
241
|
+
// offset added for rotate and scale actions
|
242
|
+
var offsetX = Math.cos(_angle + theta) * _hypotenuse,
|
243
|
+
offsetY = Math.sin(_angle + theta) * _hypotenuse,
|
244
|
+
sinTh = Math.sin(theta),
|
245
|
+
cosTh = Math.cos(theta);
|
246
|
+
|
247
|
+
var coords = this.getCenterPoint();
|
248
|
+
var tl = {
|
249
|
+
x: coords.x - offsetX,
|
250
|
+
y: coords.y - offsetY
|
251
|
+
};
|
252
|
+
var tr = {
|
253
|
+
x: tl.x + (this.currentWidth * cosTh),
|
254
|
+
y: tl.y + (this.currentWidth * sinTh)
|
255
|
+
};
|
256
|
+
var br = {
|
257
|
+
x: tr.x - (this.currentHeight * sinTh),
|
258
|
+
y: tr.y + (this.currentHeight * cosTh)
|
259
|
+
};
|
260
|
+
var bl = {
|
261
|
+
x: tl.x - (this.currentHeight * sinTh),
|
262
|
+
y: tl.y + (this.currentHeight * cosTh)
|
263
|
+
};
|
264
|
+
var ml = {
|
265
|
+
x: tl.x - (this.currentHeight/2 * sinTh),
|
266
|
+
y: tl.y + (this.currentHeight/2 * cosTh)
|
267
|
+
};
|
268
|
+
var mt = {
|
269
|
+
x: tl.x + (this.currentWidth/2 * cosTh),
|
270
|
+
y: tl.y + (this.currentWidth/2 * sinTh)
|
271
|
+
};
|
272
|
+
var mr = {
|
273
|
+
x: tr.x - (this.currentHeight/2 * sinTh),
|
274
|
+
y: tr.y + (this.currentHeight/2 * cosTh)
|
275
|
+
};
|
276
|
+
var mb = {
|
277
|
+
x: bl.x + (this.currentWidth/2 * cosTh),
|
278
|
+
y: bl.y + (this.currentWidth/2 * sinTh)
|
279
|
+
};
|
280
|
+
var mtr = {
|
281
|
+
x: tl.x + (this.currentWidth/2 * cosTh),
|
282
|
+
y: tl.y + (this.currentWidth/2 * sinTh)
|
283
|
+
};
|
284
|
+
|
285
|
+
// debugging
|
286
|
+
|
287
|
+
// setTimeout(function() {
|
288
|
+
// canvas.contextTop.fillStyle = 'green';
|
289
|
+
// canvas.contextTop.fillRect(mb.x, mb.y, 3, 3);
|
290
|
+
// canvas.contextTop.fillRect(bl.x, bl.y, 3, 3);
|
291
|
+
// canvas.contextTop.fillRect(br.x, br.y, 3, 3);
|
292
|
+
// canvas.contextTop.fillRect(tl.x, tl.y, 3, 3);
|
293
|
+
// canvas.contextTop.fillRect(tr.x, tr.y, 3, 3);
|
294
|
+
// canvas.contextTop.fillRect(ml.x, ml.y, 3, 3);
|
295
|
+
// canvas.contextTop.fillRect(mr.x, mr.y, 3, 3);
|
296
|
+
// canvas.contextTop.fillRect(mt.x, mt.y, 3, 3);
|
297
|
+
// }, 50);
|
298
|
+
|
299
|
+
// clockwise
|
300
|
+
this.oCoords = { tl: tl, tr: tr, br: br, bl: bl, ml: ml, mt: mt, mr: mr, mb: mb, mtr: mtr };
|
301
|
+
|
302
|
+
// set coordinates of the draggable boxes in the corners used to scale/rotate the image
|
303
|
+
this._setCornerCoords();
|
304
|
+
|
305
|
+
return this;
|
306
|
+
}
|
307
|
+
});
|
308
|
+
})();
|
@@ -0,0 +1,496 @@
|
|
1
|
+
(function(){
|
2
|
+
|
3
|
+
var getPointer = fabric.util.getPointer,
|
4
|
+
degreesToRadians = fabric.util.degreesToRadians;
|
5
|
+
|
6
|
+
fabric.util.object.extend(fabric.Object.prototype, /** @scope fabric.Object.prototype */ {
|
7
|
+
|
8
|
+
/**
|
9
|
+
* Determines which one of the four corners has been clicked
|
10
|
+
* @method _findTargetCorner
|
11
|
+
* @private
|
12
|
+
* @param e {Event} event object
|
13
|
+
* @param offset {Object} canvas offset
|
14
|
+
* @return {String|Boolean} corner code (tl, tr, bl, br, etc.), or false if nothing is found
|
15
|
+
*/
|
16
|
+
_findTargetCorner: function(e, offset) {
|
17
|
+
if (!this.hasControls || !this.active) return false;
|
18
|
+
|
19
|
+
var pointer = getPointer(e, this.canvas.upperCanvasEl),
|
20
|
+
ex = pointer.x - offset.left,
|
21
|
+
ey = pointer.y - offset.top,
|
22
|
+
xpoints,
|
23
|
+
lines;
|
24
|
+
|
25
|
+
for (var i in this.oCoords) {
|
26
|
+
|
27
|
+
if (i === 'mtr' && !this.hasRotatingPoint) {
|
28
|
+
continue;
|
29
|
+
}
|
30
|
+
|
31
|
+
if (this.get('lockUniScaling') && (i === 'mt' || i === 'mr' || i === 'mb' || i === 'ml')) {
|
32
|
+
continue;
|
33
|
+
}
|
34
|
+
|
35
|
+
lines = this._getImageLines(this.oCoords[i].corner, i);
|
36
|
+
|
37
|
+
// debugging
|
38
|
+
|
39
|
+
// canvas.contextTop.fillRect(lines.bottomline.d.x, lines.bottomline.d.y, 2, 2);
|
40
|
+
// canvas.contextTop.fillRect(lines.bottomline.o.x, lines.bottomline.o.y, 2, 2);
|
41
|
+
|
42
|
+
// canvas.contextTop.fillRect(lines.leftline.d.x, lines.leftline.d.y, 2, 2);
|
43
|
+
// canvas.contextTop.fillRect(lines.leftline.o.x, lines.leftline.o.y, 2, 2);
|
44
|
+
|
45
|
+
// canvas.contextTop.fillRect(lines.topline.d.x, lines.topline.d.y, 2, 2);
|
46
|
+
// canvas.contextTop.fillRect(lines.topline.o.x, lines.topline.o.y, 2, 2);
|
47
|
+
|
48
|
+
// canvas.contextTop.fillRect(lines.rightline.d.x, lines.rightline.d.y, 2, 2);
|
49
|
+
// canvas.contextTop.fillRect(lines.rightline.o.x, lines.rightline.o.y, 2, 2);
|
50
|
+
|
51
|
+
xpoints = this._findCrossPoints(ex, ey, lines);
|
52
|
+
if (xpoints % 2 === 1 && xpoints !== 0) {
|
53
|
+
this.__corner = i;
|
54
|
+
return i;
|
55
|
+
}
|
56
|
+
}
|
57
|
+
return false;
|
58
|
+
},
|
59
|
+
|
60
|
+
/**
|
61
|
+
* Helper method to determine how many cross points are between the 4 image edges
|
62
|
+
* and the horizontal line determined by the position of our mouse when clicked on canvas
|
63
|
+
* @method _findCrossPoints
|
64
|
+
* @private
|
65
|
+
* @param ex {Number} x coordinate of the mouse
|
66
|
+
* @param ey {Number} y coordinate of the mouse
|
67
|
+
* @param oCoords {Object} Coordinates of the image being evaluated
|
68
|
+
*/
|
69
|
+
_findCrossPoints: function(ex, ey, oCoords) {
|
70
|
+
var b1, b2, a1, a2, xi, yi,
|
71
|
+
xcount = 0,
|
72
|
+
iLine;
|
73
|
+
|
74
|
+
for (var lineKey in oCoords) {
|
75
|
+
iLine = oCoords[lineKey];
|
76
|
+
// optimisation 1: line below dot. no cross
|
77
|
+
if ((iLine.o.y < ey) && (iLine.d.y < ey)) {
|
78
|
+
continue;
|
79
|
+
}
|
80
|
+
// optimisation 2: line above dot. no cross
|
81
|
+
if ((iLine.o.y >= ey) && (iLine.d.y >= ey)) {
|
82
|
+
continue;
|
83
|
+
}
|
84
|
+
// optimisation 3: vertical line case
|
85
|
+
if ((iLine.o.x === iLine.d.x) && (iLine.o.x >= ex)) {
|
86
|
+
xi = iLine.o.x;
|
87
|
+
yi = ey;
|
88
|
+
}
|
89
|
+
// calculate the intersection point
|
90
|
+
else {
|
91
|
+
b1 = 0;
|
92
|
+
b2 = (iLine.d.y-iLine.o.y)/(iLine.d.x-iLine.o.x);
|
93
|
+
a1 = ey-b1*ex;
|
94
|
+
a2 = iLine.o.y-b2*iLine.o.x;
|
95
|
+
|
96
|
+
xi = - (a1-a2)/(b1-b2);
|
97
|
+
yi = a1+b1*xi;
|
98
|
+
}
|
99
|
+
// dont count xi < ex cases
|
100
|
+
if (xi >= ex) {
|
101
|
+
xcount += 1;
|
102
|
+
}
|
103
|
+
// optimisation 4: specific for square images
|
104
|
+
if (xcount === 2) {
|
105
|
+
break;
|
106
|
+
}
|
107
|
+
}
|
108
|
+
return xcount;
|
109
|
+
},
|
110
|
+
|
111
|
+
/**
|
112
|
+
* Method that returns an object with the image lines in it given the coordinates of the corners
|
113
|
+
* @method _getImageLines
|
114
|
+
* @private
|
115
|
+
* @param oCoords {Object} coordinates of the image corners
|
116
|
+
*/
|
117
|
+
_getImageLines: function(oCoords) {
|
118
|
+
return {
|
119
|
+
topline: {
|
120
|
+
o: oCoords.tl,
|
121
|
+
d: oCoords.tr
|
122
|
+
},
|
123
|
+
rightline: {
|
124
|
+
o: oCoords.tr,
|
125
|
+
d: oCoords.br
|
126
|
+
},
|
127
|
+
bottomline: {
|
128
|
+
o: oCoords.br,
|
129
|
+
d: oCoords.bl
|
130
|
+
},
|
131
|
+
leftline: {
|
132
|
+
o: oCoords.bl,
|
133
|
+
d: oCoords.tl
|
134
|
+
}
|
135
|
+
};
|
136
|
+
},
|
137
|
+
|
138
|
+
/**
|
139
|
+
* Sets the coordinates of the draggable boxes in the corners of
|
140
|
+
* the image used to scale/rotate it.
|
141
|
+
* @method _setCornerCoords
|
142
|
+
* @private
|
143
|
+
*/
|
144
|
+
_setCornerCoords: function() {
|
145
|
+
var coords = this.oCoords,
|
146
|
+
theta = degreesToRadians(this.angle),
|
147
|
+
newTheta = degreesToRadians(45 - this.angle),
|
148
|
+
cornerHypotenuse = Math.sqrt(2 * Math.pow(this.cornerSize, 2)) / 2,
|
149
|
+
cosHalfOffset = cornerHypotenuse * Math.cos(newTheta),
|
150
|
+
sinHalfOffset = cornerHypotenuse * Math.sin(newTheta),
|
151
|
+
sinTh = Math.sin(theta),
|
152
|
+
cosTh = Math.cos(theta);
|
153
|
+
|
154
|
+
coords.tl.corner = {
|
155
|
+
tl: {
|
156
|
+
x: coords.tl.x - sinHalfOffset,
|
157
|
+
y: coords.tl.y - cosHalfOffset
|
158
|
+
},
|
159
|
+
tr: {
|
160
|
+
x: coords.tl.x + cosHalfOffset,
|
161
|
+
y: coords.tl.y - sinHalfOffset
|
162
|
+
},
|
163
|
+
bl: {
|
164
|
+
x: coords.tl.x - cosHalfOffset,
|
165
|
+
y: coords.tl.y + sinHalfOffset
|
166
|
+
},
|
167
|
+
br: {
|
168
|
+
x: coords.tl.x + sinHalfOffset,
|
169
|
+
y: coords.tl.y + cosHalfOffset
|
170
|
+
}
|
171
|
+
};
|
172
|
+
|
173
|
+
coords.tr.corner = {
|
174
|
+
tl: {
|
175
|
+
x: coords.tr.x - sinHalfOffset,
|
176
|
+
y: coords.tr.y - cosHalfOffset
|
177
|
+
},
|
178
|
+
tr: {
|
179
|
+
x: coords.tr.x + cosHalfOffset,
|
180
|
+
y: coords.tr.y - sinHalfOffset
|
181
|
+
},
|
182
|
+
br: {
|
183
|
+
x: coords.tr.x + sinHalfOffset,
|
184
|
+
y: coords.tr.y + cosHalfOffset
|
185
|
+
},
|
186
|
+
bl: {
|
187
|
+
x: coords.tr.x - cosHalfOffset,
|
188
|
+
y: coords.tr.y + sinHalfOffset
|
189
|
+
}
|
190
|
+
};
|
191
|
+
|
192
|
+
coords.bl.corner = {
|
193
|
+
tl: {
|
194
|
+
x: coords.bl.x - sinHalfOffset,
|
195
|
+
y: coords.bl.y - cosHalfOffset
|
196
|
+
},
|
197
|
+
bl: {
|
198
|
+
x: coords.bl.x - cosHalfOffset,
|
199
|
+
y: coords.bl.y + sinHalfOffset
|
200
|
+
},
|
201
|
+
br: {
|
202
|
+
x: coords.bl.x + sinHalfOffset,
|
203
|
+
y: coords.bl.y + cosHalfOffset
|
204
|
+
},
|
205
|
+
tr: {
|
206
|
+
x: coords.bl.x + cosHalfOffset,
|
207
|
+
y: coords.bl.y - sinHalfOffset
|
208
|
+
}
|
209
|
+
};
|
210
|
+
|
211
|
+
coords.br.corner = {
|
212
|
+
tr: {
|
213
|
+
x: coords.br.x + cosHalfOffset,
|
214
|
+
y: coords.br.y - sinHalfOffset
|
215
|
+
},
|
216
|
+
bl: {
|
217
|
+
x: coords.br.x - cosHalfOffset,
|
218
|
+
y: coords.br.y + sinHalfOffset
|
219
|
+
},
|
220
|
+
br: {
|
221
|
+
x: coords.br.x + sinHalfOffset,
|
222
|
+
y: coords.br.y + cosHalfOffset
|
223
|
+
},
|
224
|
+
tl: {
|
225
|
+
x: coords.br.x - sinHalfOffset,
|
226
|
+
y: coords.br.y - cosHalfOffset
|
227
|
+
}
|
228
|
+
};
|
229
|
+
|
230
|
+
coords.ml.corner = {
|
231
|
+
tl: {
|
232
|
+
x: coords.ml.x - sinHalfOffset,
|
233
|
+
y: coords.ml.y - cosHalfOffset
|
234
|
+
},
|
235
|
+
tr: {
|
236
|
+
x: coords.ml.x + cosHalfOffset,
|
237
|
+
y: coords.ml.y - sinHalfOffset
|
238
|
+
},
|
239
|
+
bl: {
|
240
|
+
x: coords.ml.x - cosHalfOffset,
|
241
|
+
y: coords.ml.y + sinHalfOffset
|
242
|
+
},
|
243
|
+
br: {
|
244
|
+
x: coords.ml.x + sinHalfOffset,
|
245
|
+
y: coords.ml.y + cosHalfOffset
|
246
|
+
}
|
247
|
+
};
|
248
|
+
|
249
|
+
coords.mt.corner = {
|
250
|
+
tl: {
|
251
|
+
x: coords.mt.x - sinHalfOffset,
|
252
|
+
y: coords.mt.y - cosHalfOffset
|
253
|
+
},
|
254
|
+
tr: {
|
255
|
+
x: coords.mt.x + cosHalfOffset,
|
256
|
+
y: coords.mt.y - sinHalfOffset
|
257
|
+
},
|
258
|
+
bl: {
|
259
|
+
x: coords.mt.x - cosHalfOffset,
|
260
|
+
y: coords.mt.y + sinHalfOffset
|
261
|
+
},
|
262
|
+
br: {
|
263
|
+
x: coords.mt.x + sinHalfOffset,
|
264
|
+
y: coords.mt.y + cosHalfOffset
|
265
|
+
}
|
266
|
+
};
|
267
|
+
|
268
|
+
coords.mr.corner = {
|
269
|
+
tl: {
|
270
|
+
x: coords.mr.x - sinHalfOffset,
|
271
|
+
y: coords.mr.y - cosHalfOffset
|
272
|
+
},
|
273
|
+
tr: {
|
274
|
+
x: coords.mr.x + cosHalfOffset,
|
275
|
+
y: coords.mr.y - sinHalfOffset
|
276
|
+
},
|
277
|
+
bl: {
|
278
|
+
x: coords.mr.x - cosHalfOffset,
|
279
|
+
y: coords.mr.y + sinHalfOffset
|
280
|
+
},
|
281
|
+
br: {
|
282
|
+
x: coords.mr.x + sinHalfOffset,
|
283
|
+
y: coords.mr.y + cosHalfOffset
|
284
|
+
}
|
285
|
+
};
|
286
|
+
|
287
|
+
coords.mb.corner = {
|
288
|
+
tl: {
|
289
|
+
x: coords.mb.x - sinHalfOffset,
|
290
|
+
y: coords.mb.y - cosHalfOffset
|
291
|
+
},
|
292
|
+
tr: {
|
293
|
+
x: coords.mb.x + cosHalfOffset,
|
294
|
+
y: coords.mb.y - sinHalfOffset
|
295
|
+
},
|
296
|
+
bl: {
|
297
|
+
x: coords.mb.x - cosHalfOffset,
|
298
|
+
y: coords.mb.y + sinHalfOffset
|
299
|
+
},
|
300
|
+
br: {
|
301
|
+
x: coords.mb.x + sinHalfOffset,
|
302
|
+
y: coords.mb.y + cosHalfOffset
|
303
|
+
}
|
304
|
+
};
|
305
|
+
|
306
|
+
coords.mtr.corner = {
|
307
|
+
tl: {
|
308
|
+
x: coords.mtr.x - sinHalfOffset + (sinTh * this.rotatingPointOffset),
|
309
|
+
y: coords.mtr.y - cosHalfOffset - (cosTh * this.rotatingPointOffset)
|
310
|
+
},
|
311
|
+
tr: {
|
312
|
+
x: coords.mtr.x + cosHalfOffset + (sinTh * this.rotatingPointOffset),
|
313
|
+
y: coords.mtr.y - sinHalfOffset - (cosTh * this.rotatingPointOffset)
|
314
|
+
},
|
315
|
+
bl: {
|
316
|
+
x: coords.mtr.x - cosHalfOffset + (sinTh * this.rotatingPointOffset),
|
317
|
+
y: coords.mtr.y + sinHalfOffset - (cosTh * this.rotatingPointOffset)
|
318
|
+
},
|
319
|
+
br: {
|
320
|
+
x: coords.mtr.x + sinHalfOffset + (sinTh * this.rotatingPointOffset),
|
321
|
+
y: coords.mtr.y + cosHalfOffset - (cosTh * this.rotatingPointOffset)
|
322
|
+
}
|
323
|
+
};
|
324
|
+
},
|
325
|
+
/**
|
326
|
+
* Draws borders of an object's bounding box.
|
327
|
+
* Requires public properties: width, height
|
328
|
+
* Requires public options: padding, borderColor
|
329
|
+
* @method drawBorders
|
330
|
+
* @param {CanvasRenderingContext2D} ctx Context to draw on
|
331
|
+
* @return {fabric.Object} thisArg
|
332
|
+
* @chainable
|
333
|
+
*/
|
334
|
+
drawBorders: function(ctx) {
|
335
|
+
if (!this.hasBorders) return;
|
336
|
+
|
337
|
+
var padding = this.padding,
|
338
|
+
padding2 = padding * 2,
|
339
|
+
strokeWidth = this.strokeWidth > 1 ? this.strokeWidth : 0;
|
340
|
+
|
341
|
+
ctx.save();
|
342
|
+
|
343
|
+
ctx.globalAlpha = this.isMoving ? this.borderOpacityWhenMoving : 1;
|
344
|
+
ctx.strokeStyle = this.borderColor;
|
345
|
+
|
346
|
+
var scaleX = 1 / this._constrainScale(this.scaleX),
|
347
|
+
scaleY = 1 / this._constrainScale(this.scaleY);
|
348
|
+
|
349
|
+
ctx.lineWidth = 1 / this.borderScaleFactor;
|
350
|
+
|
351
|
+
ctx.scale(scaleX, scaleY);
|
352
|
+
|
353
|
+
var w = this.getWidth(),
|
354
|
+
h = this.getHeight();
|
355
|
+
|
356
|
+
ctx.strokeRect(
|
357
|
+
~~(-(w / 2) - padding - strokeWidth / 2 * this.scaleX) + 0.5, // offset needed to make lines look sharper
|
358
|
+
~~(-(h / 2) - padding - strokeWidth / 2 * this.scaleY) + 0.5,
|
359
|
+
~~(w + padding2 + strokeWidth * this.scaleX),
|
360
|
+
~~(h + padding2 + strokeWidth * this.scaleY)
|
361
|
+
);
|
362
|
+
|
363
|
+
if (this.hasRotatingPoint && !this.get('lockRotation') && this.hasControls) {
|
364
|
+
|
365
|
+
var rotateHeight = (
|
366
|
+
this.flipY
|
367
|
+
? h + (strokeWidth * this.scaleY) + (padding * 2)
|
368
|
+
: -h - (strokeWidth * this.scaleY) - (padding * 2)
|
369
|
+
) / 2;
|
370
|
+
|
371
|
+
ctx.beginPath();
|
372
|
+
ctx.moveTo(0, rotateHeight);
|
373
|
+
ctx.lineTo(0, rotateHeight + (this.flipY ? this.rotatingPointOffset : -this.rotatingPointOffset));
|
374
|
+
ctx.closePath();
|
375
|
+
ctx.stroke();
|
376
|
+
}
|
377
|
+
|
378
|
+
ctx.restore();
|
379
|
+
return this;
|
380
|
+
},
|
381
|
+
|
382
|
+
/**
|
383
|
+
* Draws corners of an object's bounding box.
|
384
|
+
* Requires public properties: width, height, scaleX, scaleY
|
385
|
+
* Requires public options: cornerSize, padding
|
386
|
+
* @method drawControls
|
387
|
+
* @param {CanvasRenderingContext2D} ctx Context to draw on
|
388
|
+
* @return {fabric.Object} thisArg
|
389
|
+
* @chainable
|
390
|
+
*/
|
391
|
+
drawControls: function(ctx) {
|
392
|
+
if (!this.hasControls) return;
|
393
|
+
|
394
|
+
var size = this.cornerSize,
|
395
|
+
size2 = size / 2,
|
396
|
+
strokeWidth2 = this.strokeWidth / 2,
|
397
|
+
left = -(this.width / 2),
|
398
|
+
top = -(this.height / 2),
|
399
|
+
_left,
|
400
|
+
_top,
|
401
|
+
sizeX = size / this.scaleX,
|
402
|
+
sizeY = size / this.scaleY,
|
403
|
+
paddingX = this.padding / this.scaleX,
|
404
|
+
paddingY = this.padding / this.scaleY,
|
405
|
+
scaleOffsetY = size2 / this.scaleY,
|
406
|
+
scaleOffsetX = size2 / this.scaleX,
|
407
|
+
scaleOffsetSizeX = (size2 - size) / this.scaleX,
|
408
|
+
scaleOffsetSizeY = (size2 - size) / this.scaleY,
|
409
|
+
height = this.height,
|
410
|
+
width = this.width,
|
411
|
+
methodName = this.transparentCorners ? 'strokeRect' : 'fillRect',
|
412
|
+
isVML = typeof G_vmlCanvasManager !== 'undefined';
|
413
|
+
|
414
|
+
ctx.save();
|
415
|
+
|
416
|
+
ctx.lineWidth = 1 / Math.max(this.scaleX, this.scaleY);
|
417
|
+
|
418
|
+
ctx.globalAlpha = this.isMoving ? this.borderOpacityWhenMoving : 1;
|
419
|
+
ctx.strokeStyle = ctx.fillStyle = this.cornerColor;
|
420
|
+
|
421
|
+
// top-left
|
422
|
+
_left = left - scaleOffsetX - strokeWidth2 - paddingX;
|
423
|
+
_top = top - scaleOffsetY - strokeWidth2 - paddingY;
|
424
|
+
|
425
|
+
isVML || ctx.clearRect(_left, _top, sizeX, sizeY);
|
426
|
+
ctx[methodName](_left, _top, sizeX, sizeY);
|
427
|
+
|
428
|
+
// top-right
|
429
|
+
_left = left + width - scaleOffsetX + strokeWidth2 + paddingX;
|
430
|
+
_top = top - scaleOffsetY - strokeWidth2 - paddingY;
|
431
|
+
|
432
|
+
isVML || ctx.clearRect(_left, _top, sizeX, sizeY);
|
433
|
+
ctx[methodName](_left, _top, sizeX, sizeY);
|
434
|
+
|
435
|
+
// bottom-left
|
436
|
+
_left = left - scaleOffsetX - strokeWidth2 - paddingX;
|
437
|
+
_top = top + height + scaleOffsetSizeY + strokeWidth2 + paddingY;
|
438
|
+
|
439
|
+
isVML || ctx.clearRect(_left, _top, sizeX, sizeY);
|
440
|
+
ctx[methodName](_left, _top, sizeX, sizeY);
|
441
|
+
|
442
|
+
// bottom-right
|
443
|
+
_left = left + width + scaleOffsetSizeX + strokeWidth2 + paddingX;
|
444
|
+
_top = top + height + scaleOffsetSizeY + strokeWidth2 + paddingY;
|
445
|
+
|
446
|
+
isVML || ctx.clearRect(_left, _top, sizeX, sizeY);
|
447
|
+
ctx[methodName](_left, _top, sizeX, sizeY);
|
448
|
+
|
449
|
+
if (!this.get('lockUniScaling')) {
|
450
|
+
// middle-top
|
451
|
+
_left = left + width/2 - scaleOffsetX;
|
452
|
+
_top = top - scaleOffsetY - strokeWidth2 - paddingY;
|
453
|
+
|
454
|
+
isVML || ctx.clearRect(_left, _top, sizeX, sizeY);
|
455
|
+
ctx[methodName](_left, _top, sizeX, sizeY);
|
456
|
+
|
457
|
+
// middle-bottom
|
458
|
+
_left = left + width/2 - scaleOffsetX;
|
459
|
+
_top = top + height + scaleOffsetSizeY + strokeWidth2 + paddingY;
|
460
|
+
|
461
|
+
isVML || ctx.clearRect(_left, _top, sizeX, sizeY);
|
462
|
+
ctx[methodName](_left, _top, sizeX, sizeY);
|
463
|
+
|
464
|
+
// middle-right
|
465
|
+
_left = left + width + scaleOffsetSizeX + strokeWidth2 + paddingX;
|
466
|
+
_top = top + height/2 - scaleOffsetY;
|
467
|
+
|
468
|
+
isVML || ctx.clearRect(_left, _top, sizeX, sizeY);
|
469
|
+
ctx[methodName](_left, _top, sizeX, sizeY);
|
470
|
+
|
471
|
+
// middle-left
|
472
|
+
_left = left - scaleOffsetX - strokeWidth2 - paddingX;
|
473
|
+
_top = top + height/2 - scaleOffsetY;
|
474
|
+
|
475
|
+
isVML || ctx.clearRect(_left, _top, sizeX, sizeY);
|
476
|
+
ctx[methodName](_left, _top, sizeX, sizeY);
|
477
|
+
}
|
478
|
+
|
479
|
+
// middle-top-rotate
|
480
|
+
if (this.hasRotatingPoint) {
|
481
|
+
|
482
|
+
_left = left + width/2 - scaleOffsetX;
|
483
|
+
_top = this.flipY ?
|
484
|
+
(top + height + (this.rotatingPointOffset / this.scaleY) - sizeY/2 + strokeWidth2 + paddingY)
|
485
|
+
: (top - (this.rotatingPointOffset / this.scaleY) - sizeY/2 - strokeWidth2 - paddingY);
|
486
|
+
|
487
|
+
isVML || ctx.clearRect(_left, _top, sizeX, sizeY);
|
488
|
+
ctx[methodName](_left, _top, sizeX, sizeY);
|
489
|
+
}
|
490
|
+
|
491
|
+
ctx.restore();
|
492
|
+
|
493
|
+
return this;
|
494
|
+
}
|
495
|
+
});
|
496
|
+
})();
|