fabric-rails 1.0.12.1 → 1.2.1
Sign up to get free protection for your applications and to get access to all the features.
- data/CHANGELOG.md +4 -0
- data/README.md +1 -1
- data/lib/fabric/rails/version.rb +2 -2
- data/vendor/assets/javascripts/cufon.js +1226 -0
- data/vendor/assets/javascripts/event.js +20 -20
- data/vendor/assets/javascripts/excanvas.js +1464 -0
- data/vendor/assets/javascripts/fabric.js +56 -33
- data/vendor/assets/javascripts/fabric/HEADER.js +2 -4
- data/vendor/assets/javascripts/fabric/brushes/base_brush.class.js +96 -0
- data/vendor/assets/javascripts/fabric/brushes/circle_brush.class.js +99 -0
- data/vendor/assets/javascripts/fabric/brushes/pattern_brush.class.js +55 -0
- data/vendor/assets/javascripts/fabric/{freedrawing.class.js → brushes/pencil_brush.class.js} +73 -65
- data/vendor/assets/javascripts/fabric/brushes/spray_brush.class.js +157 -0
- data/vendor/assets/javascripts/fabric/canvas.class.js +154 -135
- data/vendor/assets/javascripts/fabric/color.class.js +195 -29
- data/vendor/assets/javascripts/fabric/filters/brightness_filter.class.js +70 -0
- data/vendor/assets/javascripts/fabric/filters/convolute_filter.class.js +122 -0
- data/vendor/assets/javascripts/fabric/filters/gradienttransparency_filter.class.js +69 -0
- data/vendor/assets/javascripts/fabric/filters/grayscale_filter.class.js +61 -0
- data/vendor/assets/javascripts/fabric/filters/invert_filter.class.js +57 -0
- data/vendor/assets/javascripts/fabric/filters/noise_filter.class.js +73 -0
- data/vendor/assets/javascripts/fabric/filters/pixelate_filter.class.js +98 -0
- data/vendor/assets/javascripts/fabric/filters/removewhite_filter.class.js +86 -0
- data/vendor/assets/javascripts/fabric/filters/sepia2_filter.class.js +61 -0
- data/vendor/assets/javascripts/fabric/filters/sepia_filter.class.js +58 -0
- data/vendor/assets/javascripts/fabric/filters/tint_filter.class.js +80 -0
- data/vendor/assets/javascripts/fabric/gradient.class.js +232 -80
- data/vendor/assets/javascripts/fabric/intersection.class.js +10 -28
- data/vendor/assets/javascripts/fabric/log.js +0 -2
- data/vendor/assets/javascripts/fabric/{canvas_animation.mixin.js → mixins/canvas_animation.mixin.js} +3 -6
- data/vendor/assets/javascripts/fabric/mixins/canvas_dataurl_exporter.mixin.js +137 -0
- data/vendor/assets/javascripts/fabric/{canvas_events.mixin.js → mixins/canvas_events.mixin.js} +97 -144
- data/vendor/assets/javascripts/fabric/{canvas_gestures.mixin.js → mixins/canvas_gestures.mixin.js} +4 -8
- data/vendor/assets/javascripts/fabric/{canvas_serialization.mixin.js → mixins/canvas_serialization.mixin.js} +19 -14
- data/vendor/assets/javascripts/fabric/mixins/collection.mixin.js +137 -0
- data/vendor/assets/javascripts/fabric/{object_geometry.mixin.js → mixins/object_geometry.mixin.js} +130 -47
- data/vendor/assets/javascripts/fabric/{object_interactivity.mixin.js → mixins/object_interactivity.mixin.js} +21 -102
- data/vendor/assets/javascripts/fabric/{object_origin.mixin.js → mixins/object_origin.mixin.js} +36 -26
- data/vendor/assets/javascripts/fabric/{object_straightening.mixin.js → mixins/object_straightening.mixin.js} +4 -9
- data/vendor/assets/javascripts/fabric/{observable.mixin.js → mixins/observable.mixin.js} +27 -35
- data/vendor/assets/javascripts/fabric/mixins/stateful.mixin.js +45 -0
- data/vendor/assets/javascripts/fabric/node.js +62 -26
- data/vendor/assets/javascripts/fabric/parser.js +181 -58
- data/vendor/assets/javascripts/fabric/pattern.class.js +43 -14
- data/vendor/assets/javascripts/fabric/point.class.js +4 -43
- data/vendor/assets/javascripts/fabric/shadow.class.js +19 -19
- data/vendor/assets/javascripts/fabric/{circle.class.js → shapes/circle.class.js} +32 -29
- data/vendor/assets/javascripts/fabric/{ellipse.class.js → shapes/ellipse.class.js} +45 -27
- data/vendor/assets/javascripts/fabric/{group.class.js → shapes/group.class.js} +67 -169
- data/vendor/assets/javascripts/fabric/{image.class.js → shapes/image.class.js} +134 -72
- data/vendor/assets/javascripts/fabric/{line.class.js → shapes/line.class.js} +67 -36
- data/vendor/assets/javascripts/fabric/{object.class.js → shapes/object.class.js} +394 -252
- data/vendor/assets/javascripts/fabric/{path.class.js → shapes/path.class.js} +89 -174
- data/vendor/assets/javascripts/fabric/{path_group.class.js → shapes/path_group.class.js} +12 -18
- data/vendor/assets/javascripts/fabric/{polygon.class.js → shapes/polygon.class.js} +64 -38
- data/vendor/assets/javascripts/fabric/{polyline.class.js → shapes/polyline.class.js} +64 -39
- data/vendor/assets/javascripts/fabric/{rect.class.js → shapes/rect.class.js} +78 -112
- data/vendor/assets/javascripts/fabric/{text.class.js → shapes/text.class.js} +264 -270
- data/vendor/assets/javascripts/fabric/shapes/text.cufon.js +79 -0
- data/vendor/assets/javascripts/fabric/{triangle.class.js → shapes/triangle.class.js} +46 -26
- data/vendor/assets/javascripts/fabric/static_canvas.class.js +134 -358
- data/vendor/assets/javascripts/fabric/util/anim_ease.js +2 -31
- data/vendor/assets/javascripts/fabric/util/dom_event.js +21 -7
- data/vendor/assets/javascripts/fabric/util/dom_misc.js +49 -39
- data/vendor/assets/javascripts/fabric/util/dom_request.js +1 -2
- data/vendor/assets/javascripts/fabric/util/dom_style.js +1 -2
- data/vendor/assets/javascripts/fabric/util/lang_array.js +19 -13
- data/vendor/assets/javascripts/fabric/util/lang_class.js +1 -2
- data/vendor/assets/javascripts/fabric/util/lang_function.js +3 -1
- data/vendor/assets/javascripts/fabric/util/lang_object.js +5 -5
- data/vendor/assets/javascripts/fabric/util/lang_string.js +7 -5
- data/vendor/assets/javascripts/fabric/util/misc.js +207 -42
- metadata +47 -29
- data/vendor/assets/javascripts/fabric/image_filters.js +0 -809
- data/vendor/assets/javascripts/fabric/scout.js +0 -45
- data/vendor/assets/javascripts/fabric/stateful.js +0 -88
@@ -0,0 +1,157 @@
|
|
1
|
+
/**
|
2
|
+
* SprayBrush class
|
3
|
+
* @class fabric.SprayBrush
|
4
|
+
*/
|
5
|
+
fabric.SprayBrush = fabric.util.createClass( fabric.BaseBrush, /** @lends fabric.SprayBrush.prototype */ {
|
6
|
+
|
7
|
+
/**
|
8
|
+
* Width of a spray
|
9
|
+
* @type Number
|
10
|
+
*/
|
11
|
+
width: 10,
|
12
|
+
|
13
|
+
/**
|
14
|
+
* Density of a spray (number of dots per chunk)
|
15
|
+
* @type Number
|
16
|
+
*/
|
17
|
+
density: 20,
|
18
|
+
|
19
|
+
/**
|
20
|
+
* Width of spray dots
|
21
|
+
* @type Number
|
22
|
+
*/
|
23
|
+
dotWidth: 1,
|
24
|
+
|
25
|
+
/**
|
26
|
+
* Width variance of spray dots
|
27
|
+
* @type Number
|
28
|
+
*/
|
29
|
+
dotWidthVariance: 1,
|
30
|
+
|
31
|
+
/**
|
32
|
+
* Whether opacity of a dot should be random
|
33
|
+
* @type Boolean
|
34
|
+
*/
|
35
|
+
randomOpacity: false,
|
36
|
+
|
37
|
+
/**
|
38
|
+
* Constructor
|
39
|
+
* @param {fabric.Canvas} canvas
|
40
|
+
* @return {fabric.SprayBrush} Instance of a spray brush
|
41
|
+
*/
|
42
|
+
initialize: function(canvas) {
|
43
|
+
this.canvas = canvas;
|
44
|
+
this.sprayChunks = [ ];
|
45
|
+
},
|
46
|
+
|
47
|
+
/**
|
48
|
+
* Invoked on mouse down
|
49
|
+
* @param {Object} pointer
|
50
|
+
*/
|
51
|
+
onMouseDown: function(pointer) {
|
52
|
+
this.sprayChunks.length = 0;
|
53
|
+
this.canvas.clearContext(this.canvas.contextTop);
|
54
|
+
this.setShadowStyles();
|
55
|
+
|
56
|
+
this.addSprayChunk(pointer);
|
57
|
+
this.render();
|
58
|
+
},
|
59
|
+
|
60
|
+
/**
|
61
|
+
* Invoked on mouse move
|
62
|
+
* @param {Object} pointer
|
63
|
+
*/
|
64
|
+
onMouseMove: function(pointer) {
|
65
|
+
this.addSprayChunk(pointer);
|
66
|
+
this.render();
|
67
|
+
},
|
68
|
+
|
69
|
+
/**
|
70
|
+
* Invoked on mouse up
|
71
|
+
*/
|
72
|
+
onMouseUp: function() {
|
73
|
+
var originalRenderOnAddition = this.canvas.renderOnAddition;
|
74
|
+
this.canvas.renderOnAddition = false;
|
75
|
+
|
76
|
+
for (var i = 0, ilen = this.sprayChunks.length; i < ilen; i++) {
|
77
|
+
var sprayChunk = this.sprayChunks[i];
|
78
|
+
|
79
|
+
for (var j = 0, jlen = sprayChunk.length; j < jlen; j++) {
|
80
|
+
|
81
|
+
var rect = new fabric.Rect({
|
82
|
+
width: sprayChunk[j].width,
|
83
|
+
height: sprayChunk[j].width,
|
84
|
+
left: sprayChunk[j].x + 1,
|
85
|
+
top: sprayChunk[j].y + 1,
|
86
|
+
fill: this.color,
|
87
|
+
shadow: {
|
88
|
+
color: this.shadowColor || this.color,
|
89
|
+
blur: this.shadowBlur,
|
90
|
+
offsetX: this.shadowOffsetX,
|
91
|
+
offsetY: this.shadowOffsetY
|
92
|
+
}
|
93
|
+
});
|
94
|
+
|
95
|
+
this.canvas.add(rect);
|
96
|
+
}
|
97
|
+
}
|
98
|
+
|
99
|
+
this.canvas.clearContext(this.canvas.contextTop);
|
100
|
+
this.removeShadowStyles();
|
101
|
+
this.canvas.renderOnAddition = originalRenderOnAddition;
|
102
|
+
this.canvas.renderAll();
|
103
|
+
},
|
104
|
+
|
105
|
+
/**
|
106
|
+
* Renders brush
|
107
|
+
*/
|
108
|
+
render: function() {
|
109
|
+
var ctx = this.canvas.contextTop;
|
110
|
+
ctx.fillStyle = this.color;
|
111
|
+
ctx.save();
|
112
|
+
|
113
|
+
for (var i = 0, len = this.sprayChunkPoints.length; i < len; i++) {
|
114
|
+
var point = this.sprayChunkPoints[i];
|
115
|
+
if (typeof point.opacity !== 'undefined') {
|
116
|
+
ctx.globalAlpha = point.opacity;
|
117
|
+
}
|
118
|
+
ctx.fillRect(point.x, point.y, point.width, point.width);
|
119
|
+
}
|
120
|
+
ctx.restore();
|
121
|
+
},
|
122
|
+
|
123
|
+
/**
|
124
|
+
* @param {Object} pointer
|
125
|
+
*/
|
126
|
+
addSprayChunk: function(pointer) {
|
127
|
+
this.sprayChunkPoints = [ ];
|
128
|
+
|
129
|
+
var x, y, width, radius = this.width / 2;
|
130
|
+
|
131
|
+
for (var i = 0; i < this.density; i++) {
|
132
|
+
|
133
|
+
x = fabric.util.getRandomInt(pointer.x - radius, pointer.x + radius);
|
134
|
+
y = fabric.util.getRandomInt(pointer.y - radius, pointer.y + radius);
|
135
|
+
|
136
|
+
if (this.dotWidthVariance) {
|
137
|
+
width = fabric.util.getRandomInt(
|
138
|
+
// bottom clamp width to 1
|
139
|
+
Math.max(1, this.dotWidth - this.dotWidthVariance),
|
140
|
+
this.dotWidth + this.dotWidthVariance);
|
141
|
+
}
|
142
|
+
else {
|
143
|
+
width = this.dotWidth;
|
144
|
+
}
|
145
|
+
|
146
|
+
var point = { x: x, y: y, width: width };
|
147
|
+
|
148
|
+
if (this.randomOpacity) {
|
149
|
+
point.opacity = fabric.util.getRandomInt(0, 100) / 100;
|
150
|
+
}
|
151
|
+
|
152
|
+
this.sprayChunkPoints.push(point);
|
153
|
+
}
|
154
|
+
|
155
|
+
this.sprayChunks.push(this.sprayChunkPoints);
|
156
|
+
}
|
157
|
+
});
|
@@ -33,39 +33,34 @@
|
|
33
33
|
ProtoProxy.prototype = fabric.StaticCanvas.prototype;
|
34
34
|
fabric.Canvas.prototype = new ProtoProxy();
|
35
35
|
|
36
|
-
var InteractiveMethods = /** @
|
36
|
+
var InteractiveMethods = /** @lends fabric.Canvas.prototype */ {
|
37
37
|
|
38
38
|
/**
|
39
39
|
* When true, objects can be transformed by one side (unproportionally)
|
40
|
-
* @property
|
41
40
|
* @type Boolean
|
42
41
|
*/
|
43
42
|
uniScaleTransform: false,
|
44
43
|
|
45
44
|
/**
|
46
45
|
* When true, objects use center point as the origin of transformation
|
47
|
-
* @property
|
48
46
|
* @type Boolean
|
49
47
|
*/
|
50
48
|
centerTransform: false,
|
51
49
|
|
52
50
|
/**
|
53
51
|
* Indicates that canvas is interactive. This property should not be changed.
|
54
|
-
* @property
|
55
52
|
* @type Boolean
|
56
53
|
*/
|
57
54
|
interactive: true,
|
58
55
|
|
59
56
|
/**
|
60
57
|
* Indicates whether group selection should be enabled
|
61
|
-
* @property
|
62
58
|
* @type Boolean
|
63
59
|
*/
|
64
60
|
selection: true,
|
65
61
|
|
66
62
|
/**
|
67
63
|
* Color of selection
|
68
|
-
* @property
|
69
64
|
* @type String
|
70
65
|
*/
|
71
66
|
selectionColor: 'rgba(100, 100, 255, 0.3)', // blue
|
@@ -73,112 +68,88 @@
|
|
73
68
|
/**
|
74
69
|
* Default dash array pattern
|
75
70
|
* If not empty the selection border is dashed
|
76
|
-
* @property
|
77
71
|
* @type Array
|
78
72
|
*/
|
79
73
|
selectionDashArray: [ ],
|
80
74
|
|
81
75
|
/**
|
82
76
|
* Color of the border of selection (usually slightly darker than color of selection itself)
|
83
|
-
* @property
|
84
77
|
* @type String
|
85
78
|
*/
|
86
79
|
selectionBorderColor: 'rgba(255, 255, 255, 0.3)',
|
87
80
|
|
88
81
|
/**
|
89
82
|
* Width of a line used in object/group selection
|
90
|
-
* @property
|
91
83
|
* @type Number
|
92
84
|
*/
|
93
85
|
selectionLineWidth: 1,
|
94
86
|
|
95
|
-
/**
|
96
|
-
* Color of the line used in free drawing mode
|
97
|
-
* @property
|
98
|
-
* @type String
|
99
|
-
*/
|
100
|
-
freeDrawingColor: 'rgb(0, 0, 0)',
|
101
|
-
|
102
|
-
/**
|
103
|
-
* Width of a line used in free drawing mode
|
104
|
-
* @property
|
105
|
-
* @type Number
|
106
|
-
*/
|
107
|
-
freeDrawingLineWidth: 1,
|
108
|
-
|
109
87
|
/**
|
110
88
|
* Default cursor value used when hovering over an object on canvas
|
111
|
-
* @property
|
112
89
|
* @type String
|
113
90
|
*/
|
114
91
|
hoverCursor: 'move',
|
115
92
|
|
116
93
|
/**
|
117
94
|
* Default cursor value used when moving an object on canvas
|
118
|
-
* @property
|
119
95
|
* @type String
|
120
96
|
*/
|
121
97
|
moveCursor: 'move',
|
122
98
|
|
123
99
|
/**
|
124
100
|
* Default cursor value used for the entire canvas
|
125
|
-
* @property
|
126
101
|
* @type String
|
127
102
|
*/
|
128
103
|
defaultCursor: 'default',
|
129
104
|
|
130
105
|
/**
|
131
106
|
* Cursor value used during free drawing
|
132
|
-
* @property
|
133
107
|
* @type String
|
134
108
|
*/
|
135
109
|
freeDrawingCursor: 'crosshair',
|
136
110
|
|
137
111
|
/**
|
138
112
|
* Cursor value used for rotation point
|
139
|
-
* @property
|
140
113
|
* @type String
|
141
114
|
*/
|
142
115
|
rotationCursor: 'crosshair',
|
143
116
|
|
144
117
|
/**
|
145
118
|
* Default element class that's given to wrapper (div) element of canvas
|
146
|
-
* @property
|
147
119
|
* @type String
|
148
120
|
*/
|
149
121
|
containerClass: 'canvas-container',
|
150
122
|
|
151
123
|
/**
|
152
124
|
* When true, object detection happens on per-pixel basis rather than on per-bounding-box
|
153
|
-
* @property
|
154
125
|
* @type Boolean
|
155
126
|
*/
|
156
127
|
perPixelTargetFind: false,
|
157
128
|
|
158
129
|
/**
|
159
130
|
* Number of pixels around target pixel to tolerate (consider active) during object detection
|
160
|
-
* @property
|
161
131
|
* @type Number
|
162
132
|
*/
|
163
133
|
targetFindTolerance: 0,
|
164
134
|
|
165
135
|
/**
|
166
|
-
* @method _initInteractive
|
167
136
|
* @private
|
168
137
|
*/
|
169
138
|
_initInteractive: function() {
|
170
139
|
this._currentTransform = null;
|
171
140
|
this._groupSelector = null;
|
172
|
-
this.freeDrawing = fabric.FreeDrawing && new fabric.FreeDrawing(this);
|
173
141
|
this._initWrapperElement();
|
174
142
|
this._createUpperCanvas();
|
175
143
|
this._initEvents();
|
144
|
+
|
145
|
+
this.freeDrawingBrush = fabric.PencilBrush && new fabric.PencilBrush(this);
|
146
|
+
|
176
147
|
this.calcOffset();
|
177
148
|
},
|
178
149
|
|
179
150
|
/**
|
180
151
|
* Resets the current transform to its original values and chooses the type of resizing based on the event
|
181
|
-
* @
|
152
|
+
* @private
|
182
153
|
* @param e {Event} Event object fired on mousemove
|
183
154
|
*/
|
184
155
|
_resetCurrentTransform: function(e) {
|
@@ -189,7 +160,7 @@
|
|
189
160
|
t.target.set('left', t.original.left);
|
190
161
|
t.target.set('top', t.original.top);
|
191
162
|
|
192
|
-
if (e.altKey || this.centerTransform) {
|
163
|
+
if (e.altKey || this.centerTransform || t.target.centerTransform) {
|
193
164
|
if (t.originX !== 'center') {
|
194
165
|
if (t.originX === 'right') {
|
195
166
|
t.mouseXSign = -1;
|
@@ -217,36 +188,22 @@
|
|
217
188
|
},
|
218
189
|
|
219
190
|
/**
|
220
|
-
*
|
221
|
-
* @
|
222
|
-
* @param
|
223
|
-
* @
|
224
|
-
* @return {Boolean} true if point contains within area of given object
|
191
|
+
* Checks if point is contained within an area of given object
|
192
|
+
* @param {Event} e Event object
|
193
|
+
* @param {fabric.Object} target Object to test against
|
194
|
+
* @return {Boolean} true if point is contained within an area of given object
|
225
195
|
*/
|
226
196
|
containsPoint: function (e, target) {
|
227
197
|
var pointer = this.getPointer(e),
|
228
|
-
xy = this._normalizePointer(target, pointer)
|
229
|
-
x = xy.x,
|
230
|
-
y = xy.y;
|
198
|
+
xy = this._normalizePointer(target, pointer);
|
231
199
|
|
232
200
|
// http://www.geog.ubc.ca/courses/klink/gis.notes/ncgia/u32.html
|
233
201
|
// http://idav.ucdavis.edu/~okreylos/TAship/Spring2000/PointInPolygon.html
|
234
|
-
|
235
|
-
// we iterate through each object. If target found, return it.
|
236
|
-
var iLines = target._getImageLines(target.oCoords),
|
237
|
-
xpoints = target._findCrossPoints(x, y, iLines);
|
238
|
-
|
239
|
-
// if xcount is odd then we clicked inside the object
|
240
|
-
// For the specific case of square images xcount === 1 in all true cases
|
241
|
-
if ((xpoints && xpoints % 2 === 1) || target._findTargetCorner(e, this._offset)) {
|
242
|
-
return true;
|
243
|
-
}
|
244
|
-
return false;
|
202
|
+
return (target.containsPoint(xy) || target._findTargetCorner(e, this._offset));
|
245
203
|
},
|
246
204
|
|
247
205
|
/**
|
248
206
|
* @private
|
249
|
-
* @method _normalizePointer
|
250
207
|
*/
|
251
208
|
_normalizePointer: function (object, pointer) {
|
252
209
|
|
@@ -268,13 +225,18 @@
|
|
268
225
|
},
|
269
226
|
|
270
227
|
/**
|
271
|
-
*
|
272
|
-
* @
|
228
|
+
* Returns true if object is transparent at a certain location
|
229
|
+
* @param {fabric.Object} target Object to check
|
230
|
+
* @param {Number} x Left coordinate
|
231
|
+
* @param {Number} y Top coordinate
|
232
|
+
* @return {Boolean}
|
273
233
|
*/
|
274
|
-
|
234
|
+
isTargetTransparent: function (target, x, y) {
|
275
235
|
var cacheContext = this.contextCache;
|
276
236
|
|
277
|
-
var hasBorders = target.hasBorders,
|
237
|
+
var hasBorders = target.hasBorders,
|
238
|
+
transparentCorners = target.transparentCorners;
|
239
|
+
|
278
240
|
target.hasBorders = target.transparentCorners = false;
|
279
241
|
|
280
242
|
this._draw(cacheContext, target);
|
@@ -303,40 +265,42 @@
|
|
303
265
|
x, y, (this.targetFindTolerance * 2) || 1, (this.targetFindTolerance * 2) || 1);
|
304
266
|
|
305
267
|
// Split image data - for tolerance > 1, pixelDataSize = 4;
|
306
|
-
for (var i = 3
|
307
|
-
|
308
|
-
|
309
|
-
|
268
|
+
for (var i = 3, l = imageData.data.length; i < l; i += 4) {
|
269
|
+
var temp = imageData.data[i];
|
270
|
+
isTransparent = temp <= 0;
|
271
|
+
if (isTransparent === false) break; //Stop if colour found
|
310
272
|
}
|
311
273
|
|
312
274
|
imageData = null;
|
313
275
|
this.clearContext(cacheContext);
|
276
|
+
|
314
277
|
return isTransparent;
|
315
278
|
},
|
316
279
|
|
317
280
|
/**
|
318
281
|
* @private
|
319
|
-
* @method _shouldClearSelection
|
320
282
|
*/
|
321
|
-
_shouldClearSelection: function (e) {
|
322
|
-
var
|
323
|
-
|
283
|
+
_shouldClearSelection: function (e, target) {
|
284
|
+
var activeGroup = this.getActiveGroup();
|
285
|
+
|
324
286
|
return (
|
325
287
|
!target || (
|
326
|
-
|
327
|
-
|
328
|
-
|
329
|
-
|
330
|
-
|
331
|
-
|
288
|
+
target &&
|
289
|
+
activeGroup &&
|
290
|
+
!activeGroup.contains(target) &&
|
291
|
+
activeGroup !== target &&
|
292
|
+
!e.shiftKey) || (
|
293
|
+
target &&
|
294
|
+
!target.selectable)
|
332
295
|
);
|
333
296
|
},
|
334
297
|
|
335
298
|
/**
|
336
299
|
* @private
|
337
|
-
* @method _setupCurrentTransform
|
338
300
|
*/
|
339
301
|
_setupCurrentTransform: function (e, target) {
|
302
|
+
if (!target) return;
|
303
|
+
|
340
304
|
var action = 'drag',
|
341
305
|
corner,
|
342
306
|
pointer = getPointer(e, target.canvas.upperCanvasEl);
|
@@ -406,7 +370,7 @@
|
|
406
370
|
},
|
407
371
|
|
408
372
|
/**
|
409
|
-
* @
|
373
|
+
* @private
|
410
374
|
* @param e {Event}
|
411
375
|
* @param target {fabric.Object}
|
412
376
|
* @return {Boolean}
|
@@ -420,7 +384,6 @@
|
|
420
384
|
|
421
385
|
/**
|
422
386
|
* @private
|
423
|
-
* @method _handleGroupLogic
|
424
387
|
*/
|
425
388
|
_handleGroupLogic: function (e, target) {
|
426
389
|
if (target === this.getActiveGroup()) {
|
@@ -436,7 +399,7 @@
|
|
436
399
|
if (activeGroup.contains(target)) {
|
437
400
|
activeGroup.removeWithUpdate(target);
|
438
401
|
this._resetObjectTransform(activeGroup);
|
439
|
-
target.
|
402
|
+
target.set('active', false);
|
440
403
|
if (activeGroup.size() === 1) {
|
441
404
|
// remove group alltogether if after removal it only contains 1 object
|
442
405
|
this.discardActiveGroup();
|
@@ -447,7 +410,7 @@
|
|
447
410
|
this._resetObjectTransform(activeGroup);
|
448
411
|
}
|
449
412
|
this.fire('selection:created', { target: activeGroup, e: e });
|
450
|
-
activeGroup.
|
413
|
+
activeGroup.set('active', true);
|
451
414
|
}
|
452
415
|
else {
|
453
416
|
// group does not exist
|
@@ -455,13 +418,18 @@
|
|
455
418
|
// only if there's an active object
|
456
419
|
if (target !== this._activeObject) {
|
457
420
|
// and that object is not the actual target
|
458
|
-
var
|
421
|
+
var objects = this.getObjects();
|
422
|
+
var isActiveLower = objects.indexOf(this._activeObject) < objects.indexOf(target);
|
423
|
+
var group = new fabric.Group(
|
424
|
+
isActiveLower ? [ target, this._activeObject ] : [ this._activeObject, target ]);
|
425
|
+
|
459
426
|
this.setActiveGroup(group);
|
460
427
|
activeGroup = this.getActiveGroup();
|
428
|
+
this.fire('selection:created', { target: activeGroup, e: e });
|
461
429
|
}
|
462
430
|
}
|
463
431
|
// activate target object in any case
|
464
|
-
target.
|
432
|
+
target.set('active', true);
|
465
433
|
}
|
466
434
|
|
467
435
|
if (activeGroup) {
|
@@ -471,7 +439,7 @@
|
|
471
439
|
|
472
440
|
/**
|
473
441
|
* Translates object by "setting" its left/top
|
474
|
-
* @
|
442
|
+
* @private
|
475
443
|
* @param x {Number} pointer's x coordinate
|
476
444
|
* @param y {Number} pointer's y coordinate
|
477
445
|
*/
|
@@ -488,7 +456,7 @@
|
|
488
456
|
|
489
457
|
/**
|
490
458
|
* Scales object by invoking its scaleX/scaleY methods
|
491
|
-
* @
|
459
|
+
* @private
|
492
460
|
* @param x {Number} pointer's x coordinate
|
493
461
|
* @param y {Number} pointer's y coordinate
|
494
462
|
* @param by {String} Either 'x' or 'y' - specifies dimension constraint by which to scale an object.
|
@@ -530,14 +498,33 @@
|
|
530
498
|
}
|
531
499
|
}
|
532
500
|
|
501
|
+
// adjust the mouse coordinates when dealing with padding
|
502
|
+
if (abs(localMouse.x) > target.padding) {
|
503
|
+
if (localMouse.x < 0 ) {
|
504
|
+
localMouse.x += target.padding;
|
505
|
+
} else {
|
506
|
+
localMouse.x -= target.padding;
|
507
|
+
}
|
508
|
+
} else { // mouse is within the padding, set to 0
|
509
|
+
localMouse.x = 0;
|
510
|
+
}
|
511
|
+
|
512
|
+
if (abs(localMouse.y) > target.padding) {
|
513
|
+
if (localMouse.y < 0 ) {
|
514
|
+
localMouse.y += target.padding;
|
515
|
+
} else {
|
516
|
+
localMouse.y -= target.padding;
|
517
|
+
}
|
518
|
+
} else {
|
519
|
+
localMouse.y = 0;
|
520
|
+
}
|
521
|
+
|
533
522
|
// Actually scale the object
|
534
523
|
var newScaleX = target.scaleX, newScaleY = target.scaleY;
|
535
524
|
if (by === 'equally' && !lockScalingX && !lockScalingY) {
|
536
525
|
var dist = localMouse.y + localMouse.x;
|
537
|
-
var lastDist = (target.height) * t.original.scaleY +
|
538
|
-
(target.width) * t.original.scaleX
|
539
|
-
(target.padding * 2) -
|
540
|
-
(target.strokeWidth * 2) + 1 /* additional offset needed probably due to subpixel rendering, and avoids jerk when scaling an object */;
|
526
|
+
var lastDist = (target.height + (target.strokeWidth)) * t.original.scaleY +
|
527
|
+
(target.width + (target.strokeWidth)) * t.original.scaleX;
|
541
528
|
|
542
529
|
// We use t.scaleX/Y instead of target.scaleX/Y because the object may have a min scale and we'll loose the proportions
|
543
530
|
newScaleX = t.original.scaleX * dist/lastDist;
|
@@ -547,18 +534,18 @@
|
|
547
534
|
target.set('scaleY', newScaleY);
|
548
535
|
}
|
549
536
|
else if (!by) {
|
550
|
-
newScaleX = localMouse.x/(target.width+target.
|
551
|
-
newScaleY = localMouse.y/(target.height+target.
|
537
|
+
newScaleX = localMouse.x/(target.width+target.strokeWidth);
|
538
|
+
newScaleY = localMouse.y/(target.height+target.strokeWidth);
|
552
539
|
|
553
540
|
lockScalingX || target.set('scaleX', newScaleX);
|
554
541
|
lockScalingY || target.set('scaleY', newScaleY);
|
555
542
|
}
|
556
543
|
else if (by === 'x' && !target.get('lockUniScaling')) {
|
557
|
-
newScaleX = localMouse.x/(target.width+target.
|
544
|
+
newScaleX = localMouse.x/(target.width + target.strokeWidth);
|
558
545
|
lockScalingX || target.set('scaleX', newScaleX);
|
559
546
|
}
|
560
547
|
else if (by === 'y' && !target.get('lockUniScaling')) {
|
561
|
-
newScaleY = localMouse.y/(target.height+target.
|
548
|
+
newScaleY = localMouse.y/(target.height + target.strokeWidth);
|
562
549
|
lockScalingY || target.set('scaleY', newScaleY);
|
563
550
|
}
|
564
551
|
|
@@ -585,7 +572,7 @@
|
|
585
572
|
|
586
573
|
/**
|
587
574
|
* Rotates object by invoking its rotate method
|
588
|
-
* @
|
575
|
+
* @private
|
589
576
|
* @param x {Number} pointer's x coordinate
|
590
577
|
* @param y {Number} pointer's y coordinate
|
591
578
|
*/
|
@@ -597,22 +584,27 @@
|
|
597
584
|
if (t.target.get('lockRotation')) return;
|
598
585
|
|
599
586
|
var lastAngle = atan2(t.ey - t.top - o.top, t.ex - t.left - o.left),
|
600
|
-
curAngle = atan2(y - t.top - o.top, x - t.left - o.left)
|
587
|
+
curAngle = atan2(y - t.top - o.top, x - t.left - o.left),
|
588
|
+
angle = radiansToDegrees(curAngle - lastAngle + t.theta);
|
589
|
+
|
590
|
+
// normalize angle to positive value
|
591
|
+
if (angle < 0) {
|
592
|
+
angle = 360 + angle;
|
593
|
+
}
|
601
594
|
|
602
|
-
t.target.angle =
|
595
|
+
t.target.angle = angle;
|
603
596
|
},
|
604
597
|
|
605
598
|
/**
|
606
|
-
* @
|
599
|
+
* @private
|
607
600
|
*/
|
608
601
|
_setCursor: function (value) {
|
609
602
|
this.upperCanvasEl.style.cursor = value;
|
610
603
|
},
|
611
604
|
|
612
605
|
/**
|
613
|
-
|
614
|
-
|
615
|
-
*/
|
606
|
+
* @private
|
607
|
+
*/
|
616
608
|
_resetObjectTransform: function (target) {
|
617
609
|
target.scaleX = 1;
|
618
610
|
target.scaleY = 1;
|
@@ -620,7 +612,6 @@
|
|
620
612
|
},
|
621
613
|
|
622
614
|
/**
|
623
|
-
* @method _drawSelection
|
624
615
|
* @private
|
625
616
|
*/
|
626
617
|
_drawSelection: function () {
|
@@ -671,7 +662,6 @@
|
|
671
662
|
|
672
663
|
/**
|
673
664
|
* @private
|
674
|
-
* @method _findSelectedObjects
|
675
665
|
*/
|
676
666
|
_findSelectedObjects: function (e) {
|
677
667
|
var group = [ ],
|
@@ -681,19 +671,25 @@
|
|
681
671
|
y2 = y1 + this._groupSelector.top,
|
682
672
|
currentObject,
|
683
673
|
selectionX1Y1 = new fabric.Point(min(x1, x2), min(y1, y2)),
|
684
|
-
selectionX2Y2 = new fabric.Point(max(x1, x2), max(y1, y2))
|
674
|
+
selectionX2Y2 = new fabric.Point(max(x1, x2), max(y1, y2)),
|
675
|
+
isClick = x1 === x2 && y1 === y2;
|
685
676
|
|
686
|
-
for (var i =
|
677
|
+
for (var i = this._objects.length; i--; ) {
|
687
678
|
currentObject = this._objects[i];
|
688
679
|
|
689
680
|
if (!currentObject) continue;
|
690
681
|
|
691
682
|
if (currentObject.intersectsWithRect(selectionX1Y1, selectionX2Y2) ||
|
692
|
-
currentObject.isContainedWithinRect(selectionX1Y1, selectionX2Y2)
|
683
|
+
currentObject.isContainedWithinRect(selectionX1Y1, selectionX2Y2) ||
|
684
|
+
currentObject.containsPoint(selectionX1Y1) ||
|
685
|
+
currentObject.containsPoint(selectionX2Y2)) {
|
693
686
|
|
694
687
|
if (this.selection && currentObject.selectable) {
|
695
|
-
currentObject.
|
688
|
+
currentObject.set('active', true);
|
696
689
|
group.push(currentObject);
|
690
|
+
|
691
|
+
// only add one object if it's a click
|
692
|
+
if (isClick) break;
|
697
693
|
}
|
698
694
|
}
|
699
695
|
}
|
@@ -703,18 +699,16 @@
|
|
703
699
|
this.setActiveObject(group[0], e);
|
704
700
|
}
|
705
701
|
else if (group.length > 1) {
|
706
|
-
group = new fabric.Group(group);
|
702
|
+
group = new fabric.Group(group.reverse());
|
707
703
|
this.setActiveGroup(group);
|
708
704
|
group.saveCoords();
|
709
705
|
this.fire('selection:created', { target: group });
|
706
|
+
this.renderAll();
|
710
707
|
}
|
711
|
-
|
712
|
-
this.renderAll();
|
713
708
|
},
|
714
709
|
|
715
710
|
/**
|
716
711
|
* Method that determines what object we are clicking on
|
717
|
-
* @method findTarget
|
718
712
|
* @param {Event} e mouse event
|
719
713
|
* @param {Boolean} skipGroup when true, group is skipped and only objects are traversed through
|
720
714
|
*/
|
@@ -725,6 +719,7 @@
|
|
725
719
|
|
726
720
|
if (this.controlsAboveOverlay &&
|
727
721
|
this.lastRenderedObjectWithControlsAboveOverlay &&
|
722
|
+
this.lastRenderedObjectWithControlsAboveOverlay.visible &&
|
728
723
|
this.containsPoint(e, this.lastRenderedObjectWithControlsAboveOverlay) &&
|
729
724
|
this.lastRenderedObjectWithControlsAboveOverlay._findTargetCorner(e, this._offset)) {
|
730
725
|
target = this.lastRenderedObjectWithControlsAboveOverlay;
|
@@ -742,7 +737,7 @@
|
|
742
737
|
// Cache all targets where their bounding box contains point.
|
743
738
|
var possibleTargets = [];
|
744
739
|
for (var i = this._objects.length; i--; ) {
|
745
|
-
if (this._objects[i] && this.containsPoint(e, this._objects[i])) {
|
740
|
+
if (this._objects[i] && this._objects[i].visible && this.containsPoint(e, this._objects[i])) {
|
746
741
|
if (this.perPixelTargetFind || this._objects[i].perPixelTargetFind) {
|
747
742
|
possibleTargets[possibleTargets.length] = this._objects[i];
|
748
743
|
}
|
@@ -755,21 +750,19 @@
|
|
755
750
|
}
|
756
751
|
for (var j = 0, len = possibleTargets.length; j < len; j++) {
|
757
752
|
pointer = this.getPointer(e);
|
758
|
-
var isTransparent = this.
|
753
|
+
var isTransparent = this.isTargetTransparent(possibleTargets[j], pointer.x, pointer.y);
|
759
754
|
if (!isTransparent) {
|
760
755
|
target = possibleTargets[j];
|
761
756
|
this.relatedTarget = target;
|
762
757
|
break;
|
763
758
|
}
|
764
759
|
}
|
765
|
-
|
766
|
-
|
767
|
-
}
|
760
|
+
|
761
|
+
return target;
|
768
762
|
},
|
769
763
|
|
770
764
|
/**
|
771
765
|
* Returns pointer coordinates relative to canvas.
|
772
|
-
* @method getPointer
|
773
766
|
* @param {Event} e
|
774
767
|
* @return {Object} object with "x" and "y" number values
|
775
768
|
*/
|
@@ -783,23 +776,24 @@
|
|
783
776
|
|
784
777
|
/**
|
785
778
|
* @private
|
786
|
-
* @method _createUpperCanvas
|
787
779
|
* @param {HTMLElement|String} canvasEl Canvas element
|
788
780
|
* @throws {CANVAS_INIT_ERROR} If canvas can not be initialized
|
789
781
|
*/
|
790
782
|
_createUpperCanvas: function () {
|
783
|
+
var lowerCanvasClass = this.lowerCanvasEl.className.replace(/\s*lower-canvas\s*/, '');
|
784
|
+
|
791
785
|
this.upperCanvasEl = this._createCanvasElement();
|
792
|
-
this.upperCanvasEl
|
786
|
+
fabric.util.addClass(this.upperCanvasEl, 'upper-canvas ' + lowerCanvasClass);
|
793
787
|
|
794
788
|
this.wrapperEl.appendChild(this.upperCanvasEl);
|
795
789
|
|
790
|
+
this._copyCanvasStyle(this.lowerCanvasEl, this.upperCanvasEl);
|
796
791
|
this._applyCanvasStyle(this.upperCanvasEl);
|
797
792
|
this.contextTop = this.upperCanvasEl.getContext('2d');
|
798
793
|
},
|
799
794
|
|
800
795
|
/**
|
801
796
|
* @private
|
802
|
-
* @method _createCacheCanvas
|
803
797
|
*/
|
804
798
|
_createCacheCanvas: function () {
|
805
799
|
this.cacheCanvasEl = this._createCanvasElement();
|
@@ -810,7 +804,6 @@
|
|
810
804
|
|
811
805
|
/**
|
812
806
|
* @private
|
813
|
-
* @method _initWrapperElement
|
814
807
|
* @param {Number} width
|
815
808
|
* @param {Number} height
|
816
809
|
*/
|
@@ -828,7 +821,6 @@
|
|
828
821
|
|
829
822
|
/**
|
830
823
|
* @private
|
831
|
-
* @method _applyCanvasStyle
|
832
824
|
* @param {Element} element
|
833
825
|
*/
|
834
826
|
_applyCanvasStyle: function (element) {
|
@@ -847,9 +839,18 @@
|
|
847
839
|
fabric.util.makeElementUnselectable(element);
|
848
840
|
},
|
849
841
|
|
842
|
+
/**
|
843
|
+
* Copys the the entire inline style from one element (fromEl) to another (toEl)
|
844
|
+
* @private
|
845
|
+
* @param {Element} fromEl Element style is copied from
|
846
|
+
* @param {Element} toEl Element copied style is applied to
|
847
|
+
*/
|
848
|
+
_copyCanvasStyle: function (fromEl, toEl) {
|
849
|
+
toEl.style.cssText = fromEl.style.cssText;
|
850
|
+
},
|
851
|
+
|
850
852
|
/**
|
851
853
|
* Returns context of canvas where object selection is drawn
|
852
|
-
* @method getSelectionContext
|
853
854
|
* @return {CanvasRenderingContext2D}
|
854
855
|
*/
|
855
856
|
getSelectionContext: function() {
|
@@ -858,7 +859,6 @@
|
|
858
859
|
|
859
860
|
/**
|
860
861
|
* Returns <canvas> element on which object selection is drawn
|
861
|
-
* @method getSelectionElement
|
862
862
|
* @return {HTMLCanvasElement}
|
863
863
|
*/
|
864
864
|
getSelectionElement: function () {
|
@@ -866,18 +866,17 @@
|
|
866
866
|
},
|
867
867
|
|
868
868
|
/**
|
869
|
-
* Sets given object as active
|
870
|
-
* @method setActiveObject
|
869
|
+
* Sets given object as the only active object on canvas
|
871
870
|
* @param object {fabric.Object} Object to set as an active one
|
872
871
|
* @return {fabric.Canvas} thisArg
|
873
872
|
* @chainable
|
874
873
|
*/
|
875
874
|
setActiveObject: function (object, e) {
|
876
875
|
if (this._activeObject) {
|
877
|
-
this._activeObject.
|
876
|
+
this._activeObject.set('active', false);
|
878
877
|
}
|
879
878
|
this._activeObject = object;
|
880
|
-
object.
|
879
|
+
object.set('active', true);
|
881
880
|
|
882
881
|
this.renderAll();
|
883
882
|
|
@@ -888,7 +887,6 @@
|
|
888
887
|
|
889
888
|
/**
|
890
889
|
* Returns currently active object
|
891
|
-
* @method getActiveObject
|
892
890
|
* @return {fabric.Object} active object
|
893
891
|
*/
|
894
892
|
getActiveObject: function () {
|
@@ -897,13 +895,12 @@
|
|
897
895
|
|
898
896
|
/**
|
899
897
|
* Discards currently active object
|
900
|
-
* @method discardActiveObject
|
901
898
|
* @return {fabric.Canvas} thisArg
|
902
899
|
* @chainable
|
903
900
|
*/
|
904
901
|
discardActiveObject: function () {
|
905
902
|
if (this._activeObject) {
|
906
|
-
this._activeObject.
|
903
|
+
this._activeObject.set('active', false);
|
907
904
|
}
|
908
905
|
this._activeObject = null;
|
909
906
|
return this;
|
@@ -911,7 +908,6 @@
|
|
911
908
|
|
912
909
|
/**
|
913
910
|
* Sets active group to a speicified one
|
914
|
-
* @method setActiveGroup
|
915
911
|
* @param {fabric.Group} group Group to set as a current one
|
916
912
|
* @return {fabric.Canvas} thisArg
|
917
913
|
* @chainable
|
@@ -920,14 +916,13 @@
|
|
920
916
|
this._activeGroup = group;
|
921
917
|
if (group) {
|
922
918
|
group.canvas = this;
|
923
|
-
group.
|
919
|
+
group.set('active', true);
|
924
920
|
}
|
925
921
|
return this;
|
926
922
|
},
|
927
923
|
|
928
924
|
/**
|
929
925
|
* Returns currently active group
|
930
|
-
* @method getActiveGroup
|
931
926
|
* @return {fabric.Group} Current group
|
932
927
|
*/
|
933
928
|
getActiveGroup: function () {
|
@@ -936,7 +931,6 @@
|
|
936
931
|
|
937
932
|
/**
|
938
933
|
* Removes currently active group
|
939
|
-
* @method discardActiveGroup
|
940
934
|
* @return {fabric.Canvas} thisArg
|
941
935
|
*/
|
942
936
|
discardActiveGroup: function () {
|
@@ -948,8 +942,7 @@
|
|
948
942
|
},
|
949
943
|
|
950
944
|
/**
|
951
|
-
* Deactivates all objects
|
952
|
-
* @method deactivateAll
|
945
|
+
* Deactivates all objects on canvas, removing any active group or object
|
953
946
|
* @return {fabric.Canvas} thisArg
|
954
947
|
*/
|
955
948
|
deactivateAll: function () {
|
@@ -957,7 +950,7 @@
|
|
957
950
|
i = 0,
|
958
951
|
len = allObjects.length;
|
959
952
|
for ( ; i < len; i++) {
|
960
|
-
allObjects[i].
|
953
|
+
allObjects[i].set('active', false);
|
961
954
|
}
|
962
955
|
this.discardActiveGroup();
|
963
956
|
this.discardActiveObject();
|
@@ -966,7 +959,6 @@
|
|
966
959
|
|
967
960
|
/**
|
968
961
|
* Deactivates all objects and dispatches appropriate events
|
969
|
-
* @method deactivateAllWithDispatch
|
970
962
|
* @return {fabric.Canvas} thisArg
|
971
963
|
*/
|
972
964
|
deactivateAllWithDispatch: function () {
|
@@ -979,6 +971,32 @@
|
|
979
971
|
this.fire('selection:cleared');
|
980
972
|
}
|
981
973
|
return this;
|
974
|
+
},
|
975
|
+
|
976
|
+
/**
|
977
|
+
* Draws objects' controls (borders/controls)
|
978
|
+
* @param {Object} ctx context to render controls on
|
979
|
+
*/
|
980
|
+
drawControls: function(ctx) {
|
981
|
+
var activeGroup = this.getActiveGroup();
|
982
|
+
if (activeGroup) {
|
983
|
+
ctx.save();
|
984
|
+
fabric.Group.prototype.transform.call(activeGroup, ctx);
|
985
|
+
activeGroup.drawBorders(ctx).drawControls(ctx);
|
986
|
+
ctx.restore();
|
987
|
+
}
|
988
|
+
else {
|
989
|
+
for (var i = 0, len = this._objects.length; i < len; ++i) {
|
990
|
+
if (!this._objects[i] || !this._objects[i].active) continue;
|
991
|
+
|
992
|
+
ctx.save();
|
993
|
+
fabric.Object.prototype.transform.call(this._objects[i], ctx);
|
994
|
+
this._objects[i].drawBorders(ctx).drawControls(ctx);
|
995
|
+
ctx.restore();
|
996
|
+
|
997
|
+
this.lastRenderedObjectWithControlsAboveOverlay = this._objects[i];
|
998
|
+
}
|
999
|
+
}
|
982
1000
|
}
|
983
1001
|
};
|
984
1002
|
|
@@ -994,6 +1012,7 @@
|
|
994
1012
|
}
|
995
1013
|
|
996
1014
|
if (fabric.isTouchSupported) {
|
1015
|
+
/** @ignore */
|
997
1016
|
fabric.Canvas.prototype._setCursorFromEvent = function() { };
|
998
1017
|
}
|
999
1018
|
|