fabric-rails 1.0.12 → 1.0.12.1
Sign up to get free protection for your applications and to get access to all the features.
- 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
|
+
})();
|