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,31 @@
|
|
1
|
+
/*! Fabric.js Copyright 2008-2013, Printio (Juriy Zaytsev, Maxim Chernyak) */
|
2
|
+
|
3
|
+
var fabric = fabric || { version: "1.0.12" };
|
4
|
+
|
5
|
+
if (typeof exports !== 'undefined') {
|
6
|
+
exports.fabric = fabric;
|
7
|
+
}
|
8
|
+
|
9
|
+
if (typeof document !== 'undefined' && typeof window !== 'undefined') {
|
10
|
+
fabric.document = document;
|
11
|
+
fabric.window = window;
|
12
|
+
}
|
13
|
+
else {
|
14
|
+
// assume we're running under node.js when document/window are not present
|
15
|
+
fabric.document = require("jsdom").jsdom("<!DOCTYPE html><html><head></head><body></body></html>");
|
16
|
+
fabric.window = fabric.document.createWindow();
|
17
|
+
}
|
18
|
+
|
19
|
+
/**
|
20
|
+
* True when in environment that supports touch events
|
21
|
+
* @property isTouchSupported
|
22
|
+
* @type boolean
|
23
|
+
*/
|
24
|
+
fabric.isTouchSupported = "ontouchstart" in fabric.document.documentElement;
|
25
|
+
|
26
|
+
/**
|
27
|
+
* True when in environment that's probably Node.js
|
28
|
+
* @property isLikelyNode
|
29
|
+
* @type boolean
|
30
|
+
*/
|
31
|
+
fabric.isLikelyNode = typeof Buffer !== 'undefined' && typeof window === 'undefined';
|
@@ -0,0 +1,1007 @@
|
|
1
|
+
(function() {
|
2
|
+
|
3
|
+
var extend = fabric.util.object.extend,
|
4
|
+
getPointer = fabric.util.getPointer,
|
5
|
+
degreesToRadians = fabric.util.degreesToRadians,
|
6
|
+
radiansToDegrees = fabric.util.radiansToDegrees,
|
7
|
+
atan2 = Math.atan2,
|
8
|
+
abs = Math.abs,
|
9
|
+
min = Math.min,
|
10
|
+
max = Math.max,
|
11
|
+
|
12
|
+
STROKE_OFFSET = 0.5;
|
13
|
+
|
14
|
+
/**
|
15
|
+
* Canvas class
|
16
|
+
* @class fabric.Canvas
|
17
|
+
* @constructor
|
18
|
+
* @extends fabric.StaticCanvas
|
19
|
+
* @param {HTMLElement | String} el <canvas> element to initialize instance on
|
20
|
+
* @param {Object} [options] Options object
|
21
|
+
*/
|
22
|
+
fabric.Canvas = function(el, options) {
|
23
|
+
options || (options = { });
|
24
|
+
|
25
|
+
this._initStatic(el, options);
|
26
|
+
this._initInteractive();
|
27
|
+
this._createCacheCanvas();
|
28
|
+
|
29
|
+
fabric.Canvas.activeInstance = this;
|
30
|
+
};
|
31
|
+
|
32
|
+
function ProtoProxy(){ }
|
33
|
+
ProtoProxy.prototype = fabric.StaticCanvas.prototype;
|
34
|
+
fabric.Canvas.prototype = new ProtoProxy();
|
35
|
+
|
36
|
+
var InteractiveMethods = /** @scope fabric.Canvas.prototype */ {
|
37
|
+
|
38
|
+
/**
|
39
|
+
* When true, objects can be transformed by one side (unproportionally)
|
40
|
+
* @property
|
41
|
+
* @type Boolean
|
42
|
+
*/
|
43
|
+
uniScaleTransform: false,
|
44
|
+
|
45
|
+
/**
|
46
|
+
* When true, objects use center point as the origin of transformation
|
47
|
+
* @property
|
48
|
+
* @type Boolean
|
49
|
+
*/
|
50
|
+
centerTransform: false,
|
51
|
+
|
52
|
+
/**
|
53
|
+
* Indicates that canvas is interactive. This property should not be changed.
|
54
|
+
* @property
|
55
|
+
* @type Boolean
|
56
|
+
*/
|
57
|
+
interactive: true,
|
58
|
+
|
59
|
+
/**
|
60
|
+
* Indicates whether group selection should be enabled
|
61
|
+
* @property
|
62
|
+
* @type Boolean
|
63
|
+
*/
|
64
|
+
selection: true,
|
65
|
+
|
66
|
+
/**
|
67
|
+
* Color of selection
|
68
|
+
* @property
|
69
|
+
* @type String
|
70
|
+
*/
|
71
|
+
selectionColor: 'rgba(100, 100, 255, 0.3)', // blue
|
72
|
+
|
73
|
+
/**
|
74
|
+
* Default dash array pattern
|
75
|
+
* If not empty the selection border is dashed
|
76
|
+
* @property
|
77
|
+
* @type Array
|
78
|
+
*/
|
79
|
+
selectionDashArray: [ ],
|
80
|
+
|
81
|
+
/**
|
82
|
+
* Color of the border of selection (usually slightly darker than color of selection itself)
|
83
|
+
* @property
|
84
|
+
* @type String
|
85
|
+
*/
|
86
|
+
selectionBorderColor: 'rgba(255, 255, 255, 0.3)',
|
87
|
+
|
88
|
+
/**
|
89
|
+
* Width of a line used in object/group selection
|
90
|
+
* @property
|
91
|
+
* @type Number
|
92
|
+
*/
|
93
|
+
selectionLineWidth: 1,
|
94
|
+
|
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
|
+
/**
|
110
|
+
* Default cursor value used when hovering over an object on canvas
|
111
|
+
* @property
|
112
|
+
* @type String
|
113
|
+
*/
|
114
|
+
hoverCursor: 'move',
|
115
|
+
|
116
|
+
/**
|
117
|
+
* Default cursor value used when moving an object on canvas
|
118
|
+
* @property
|
119
|
+
* @type String
|
120
|
+
*/
|
121
|
+
moveCursor: 'move',
|
122
|
+
|
123
|
+
/**
|
124
|
+
* Default cursor value used for the entire canvas
|
125
|
+
* @property
|
126
|
+
* @type String
|
127
|
+
*/
|
128
|
+
defaultCursor: 'default',
|
129
|
+
|
130
|
+
/**
|
131
|
+
* Cursor value used during free drawing
|
132
|
+
* @property
|
133
|
+
* @type String
|
134
|
+
*/
|
135
|
+
freeDrawingCursor: 'crosshair',
|
136
|
+
|
137
|
+
/**
|
138
|
+
* Cursor value used for rotation point
|
139
|
+
* @property
|
140
|
+
* @type String
|
141
|
+
*/
|
142
|
+
rotationCursor: 'crosshair',
|
143
|
+
|
144
|
+
/**
|
145
|
+
* Default element class that's given to wrapper (div) element of canvas
|
146
|
+
* @property
|
147
|
+
* @type String
|
148
|
+
*/
|
149
|
+
containerClass: 'canvas-container',
|
150
|
+
|
151
|
+
/**
|
152
|
+
* When true, object detection happens on per-pixel basis rather than on per-bounding-box
|
153
|
+
* @property
|
154
|
+
* @type Boolean
|
155
|
+
*/
|
156
|
+
perPixelTargetFind: false,
|
157
|
+
|
158
|
+
/**
|
159
|
+
* Number of pixels around target pixel to tolerate (consider active) during object detection
|
160
|
+
* @property
|
161
|
+
* @type Number
|
162
|
+
*/
|
163
|
+
targetFindTolerance: 0,
|
164
|
+
|
165
|
+
/**
|
166
|
+
* @method _initInteractive
|
167
|
+
* @private
|
168
|
+
*/
|
169
|
+
_initInteractive: function() {
|
170
|
+
this._currentTransform = null;
|
171
|
+
this._groupSelector = null;
|
172
|
+
this.freeDrawing = fabric.FreeDrawing && new fabric.FreeDrawing(this);
|
173
|
+
this._initWrapperElement();
|
174
|
+
this._createUpperCanvas();
|
175
|
+
this._initEvents();
|
176
|
+
this.calcOffset();
|
177
|
+
},
|
178
|
+
|
179
|
+
/**
|
180
|
+
* Resets the current transform to its original values and chooses the type of resizing based on the event
|
181
|
+
* @method _resetCurrentTransform
|
182
|
+
* @param e {Event} Event object fired on mousemove
|
183
|
+
*/
|
184
|
+
_resetCurrentTransform: function(e) {
|
185
|
+
var t = this._currentTransform;
|
186
|
+
|
187
|
+
t.target.set('scaleX', t.original.scaleX);
|
188
|
+
t.target.set('scaleY', t.original.scaleY);
|
189
|
+
t.target.set('left', t.original.left);
|
190
|
+
t.target.set('top', t.original.top);
|
191
|
+
|
192
|
+
if (e.altKey || this.centerTransform) {
|
193
|
+
if (t.originX !== 'center') {
|
194
|
+
if (t.originX === 'right') {
|
195
|
+
t.mouseXSign = -1;
|
196
|
+
}
|
197
|
+
else {
|
198
|
+
t.mouseXSign = 1;
|
199
|
+
}
|
200
|
+
}
|
201
|
+
if (t.originY !== 'center') {
|
202
|
+
if (t.originY === 'bottom') {
|
203
|
+
t.mouseYSign = -1;
|
204
|
+
}
|
205
|
+
else {
|
206
|
+
t.mouseYSign = 1;
|
207
|
+
}
|
208
|
+
}
|
209
|
+
|
210
|
+
t.originX = 'center';
|
211
|
+
t.originY = 'center';
|
212
|
+
}
|
213
|
+
else {
|
214
|
+
t.originX = t.original.originX;
|
215
|
+
t.originY = t.original.originY;
|
216
|
+
}
|
217
|
+
},
|
218
|
+
|
219
|
+
/**
|
220
|
+
* Applies one implementation of 'point inside polygon' algorithm
|
221
|
+
* @method containsPoint
|
222
|
+
* @param e { Event } event object
|
223
|
+
* @param target { fabric.Object } object to test against
|
224
|
+
* @return {Boolean} true if point contains within area of given object
|
225
|
+
*/
|
226
|
+
containsPoint: function (e, target) {
|
227
|
+
var pointer = this.getPointer(e),
|
228
|
+
xy = this._normalizePointer(target, pointer),
|
229
|
+
x = xy.x,
|
230
|
+
y = xy.y;
|
231
|
+
|
232
|
+
// http://www.geog.ubc.ca/courses/klink/gis.notes/ncgia/u32.html
|
233
|
+
// 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;
|
245
|
+
},
|
246
|
+
|
247
|
+
/**
|
248
|
+
* @private
|
249
|
+
* @method _normalizePointer
|
250
|
+
*/
|
251
|
+
_normalizePointer: function (object, pointer) {
|
252
|
+
|
253
|
+
var activeGroup = this.getActiveGroup(),
|
254
|
+
x = pointer.x,
|
255
|
+
y = pointer.y;
|
256
|
+
|
257
|
+
var isObjectInGroup = (
|
258
|
+
activeGroup &&
|
259
|
+
object.type !== 'group' &&
|
260
|
+
activeGroup.contains(object)
|
261
|
+
);
|
262
|
+
|
263
|
+
if (isObjectInGroup) {
|
264
|
+
x -= activeGroup.left;
|
265
|
+
y -= activeGroup.top;
|
266
|
+
}
|
267
|
+
return { x: x, y: y };
|
268
|
+
},
|
269
|
+
|
270
|
+
/**
|
271
|
+
* @private
|
272
|
+
* @method _isTargetTransparent
|
273
|
+
*/
|
274
|
+
_isTargetTransparent: function (target, x, y) {
|
275
|
+
var cacheContext = this.contextCache;
|
276
|
+
|
277
|
+
var hasBorders = target.hasBorders, transparentCorners = target.transparentCorners;
|
278
|
+
target.hasBorders = target.transparentCorners = false;
|
279
|
+
|
280
|
+
this._draw(cacheContext, target);
|
281
|
+
|
282
|
+
target.hasBorders = hasBorders;
|
283
|
+
target.transparentCorners = transparentCorners;
|
284
|
+
|
285
|
+
// If tolerance is > 0 adjust start coords to take into account. If moves off Canvas fix to 0
|
286
|
+
if (this.targetFindTolerance > 0) {
|
287
|
+
if (x > this.targetFindTolerance) {
|
288
|
+
x -= this.targetFindTolerance;
|
289
|
+
}
|
290
|
+
else {
|
291
|
+
x = 0;
|
292
|
+
}
|
293
|
+
if (y > this.targetFindTolerance) {
|
294
|
+
y -= this.targetFindTolerance;
|
295
|
+
}
|
296
|
+
else {
|
297
|
+
y = 0;
|
298
|
+
}
|
299
|
+
}
|
300
|
+
|
301
|
+
var isTransparent = true;
|
302
|
+
var imageData = cacheContext.getImageData(
|
303
|
+
x, y, (this.targetFindTolerance * 2) || 1, (this.targetFindTolerance * 2) || 1);
|
304
|
+
|
305
|
+
// Split image data - for tolerance > 1, pixelDataSize = 4;
|
306
|
+
for (var i = 3; i < imageData.data.length; i += 4) {
|
307
|
+
var temp = imageData.data[i];
|
308
|
+
isTransparent = temp <= 0;
|
309
|
+
if (isTransparent === false) break; //Stop if colour found
|
310
|
+
}
|
311
|
+
|
312
|
+
imageData = null;
|
313
|
+
this.clearContext(cacheContext);
|
314
|
+
return isTransparent;
|
315
|
+
},
|
316
|
+
|
317
|
+
/**
|
318
|
+
* @private
|
319
|
+
* @method _shouldClearSelection
|
320
|
+
*/
|
321
|
+
_shouldClearSelection: function (e) {
|
322
|
+
var target = this.findTarget(e),
|
323
|
+
activeGroup = this.getActiveGroup();
|
324
|
+
return (
|
325
|
+
!target || (
|
326
|
+
target &&
|
327
|
+
activeGroup &&
|
328
|
+
!activeGroup.contains(target) &&
|
329
|
+
activeGroup !== target &&
|
330
|
+
!e.shiftKey
|
331
|
+
)
|
332
|
+
);
|
333
|
+
},
|
334
|
+
|
335
|
+
/**
|
336
|
+
* @private
|
337
|
+
* @method _setupCurrentTransform
|
338
|
+
*/
|
339
|
+
_setupCurrentTransform: function (e, target) {
|
340
|
+
var action = 'drag',
|
341
|
+
corner,
|
342
|
+
pointer = getPointer(e, target.canvas.upperCanvasEl);
|
343
|
+
|
344
|
+
corner = target._findTargetCorner(e, this._offset);
|
345
|
+
if (corner) {
|
346
|
+
action = (corner === 'ml' || corner === 'mr')
|
347
|
+
? 'scaleX'
|
348
|
+
: (corner === 'mt' || corner === 'mb')
|
349
|
+
? 'scaleY'
|
350
|
+
: corner === 'mtr'
|
351
|
+
? 'rotate'
|
352
|
+
: 'scale';
|
353
|
+
}
|
354
|
+
|
355
|
+
var originX = "center", originY = "center";
|
356
|
+
|
357
|
+
if (corner === 'ml' || corner === 'tl' || corner === 'bl') {
|
358
|
+
originX = "right";
|
359
|
+
}
|
360
|
+
else if (corner === 'mr' || corner === 'tr' || corner === 'br') {
|
361
|
+
originX = "left";
|
362
|
+
}
|
363
|
+
|
364
|
+
if (corner === 'tl' || corner === 'mt' || corner === 'tr') {
|
365
|
+
originY = "bottom";
|
366
|
+
}
|
367
|
+
else if (corner === 'bl' || corner === 'mb' || corner === 'br') {
|
368
|
+
originY = "top";
|
369
|
+
}
|
370
|
+
|
371
|
+
if (corner === 'mtr') {
|
372
|
+
originX = 'center';
|
373
|
+
originY = 'center';
|
374
|
+
}
|
375
|
+
|
376
|
+
// var center = target.getCenterPoint();
|
377
|
+
this._currentTransform = {
|
378
|
+
target: target,
|
379
|
+
action: action,
|
380
|
+
scaleX: target.scaleX,
|
381
|
+
scaleY: target.scaleY,
|
382
|
+
offsetX: pointer.x - target.left,
|
383
|
+
offsetY: pointer.y - target.top,
|
384
|
+
originX: originX,
|
385
|
+
originY: originY,
|
386
|
+
ex: pointer.x,
|
387
|
+
ey: pointer.y,
|
388
|
+
left: target.left,
|
389
|
+
top: target.top,
|
390
|
+
theta: degreesToRadians(target.angle),
|
391
|
+
width: target.width * target.scaleX,
|
392
|
+
mouseXSign: 1,
|
393
|
+
mouseYSign: 1
|
394
|
+
};
|
395
|
+
|
396
|
+
this._currentTransform.original = {
|
397
|
+
left: target.left,
|
398
|
+
top: target.top,
|
399
|
+
scaleX: target.scaleX,
|
400
|
+
scaleY: target.scaleY,
|
401
|
+
originX: originX,
|
402
|
+
originY: originY
|
403
|
+
};
|
404
|
+
|
405
|
+
this._resetCurrentTransform(e);
|
406
|
+
},
|
407
|
+
|
408
|
+
/**
|
409
|
+
* @method _shouldHandleGroupLogic
|
410
|
+
* @param e {Event}
|
411
|
+
* @param target {fabric.Object}
|
412
|
+
* @return {Boolean}
|
413
|
+
*/
|
414
|
+
_shouldHandleGroupLogic: function(e, target) {
|
415
|
+
var activeObject = this.getActiveObject();
|
416
|
+
return e.shiftKey &&
|
417
|
+
(this.getActiveGroup() || (activeObject && activeObject !== target))
|
418
|
+
&& this.selection;
|
419
|
+
},
|
420
|
+
|
421
|
+
/**
|
422
|
+
* @private
|
423
|
+
* @method _handleGroupLogic
|
424
|
+
*/
|
425
|
+
_handleGroupLogic: function (e, target) {
|
426
|
+
if (target === this.getActiveGroup()) {
|
427
|
+
// if it's a group, find target again, this time skipping group
|
428
|
+
target = this.findTarget(e, true);
|
429
|
+
// if even object is not found, bail out
|
430
|
+
if (!target || target.isType('group')) {
|
431
|
+
return;
|
432
|
+
}
|
433
|
+
}
|
434
|
+
var activeGroup = this.getActiveGroup();
|
435
|
+
if (activeGroup) {
|
436
|
+
if (activeGroup.contains(target)) {
|
437
|
+
activeGroup.removeWithUpdate(target);
|
438
|
+
this._resetObjectTransform(activeGroup);
|
439
|
+
target.setActive(false);
|
440
|
+
if (activeGroup.size() === 1) {
|
441
|
+
// remove group alltogether if after removal it only contains 1 object
|
442
|
+
this.discardActiveGroup();
|
443
|
+
}
|
444
|
+
}
|
445
|
+
else {
|
446
|
+
activeGroup.addWithUpdate(target);
|
447
|
+
this._resetObjectTransform(activeGroup);
|
448
|
+
}
|
449
|
+
this.fire('selection:created', { target: activeGroup, e: e });
|
450
|
+
activeGroup.setActive(true);
|
451
|
+
}
|
452
|
+
else {
|
453
|
+
// group does not exist
|
454
|
+
if (this._activeObject) {
|
455
|
+
// only if there's an active object
|
456
|
+
if (target !== this._activeObject) {
|
457
|
+
// and that object is not the actual target
|
458
|
+
var group = new fabric.Group([ this._activeObject, target ]);
|
459
|
+
this.setActiveGroup(group);
|
460
|
+
activeGroup = this.getActiveGroup();
|
461
|
+
}
|
462
|
+
}
|
463
|
+
// activate target object in any case
|
464
|
+
target.setActive(true);
|
465
|
+
}
|
466
|
+
|
467
|
+
if (activeGroup) {
|
468
|
+
activeGroup.saveCoords();
|
469
|
+
}
|
470
|
+
},
|
471
|
+
|
472
|
+
/**
|
473
|
+
* Translates object by "setting" its left/top
|
474
|
+
* @method _translateObject
|
475
|
+
* @param x {Number} pointer's x coordinate
|
476
|
+
* @param y {Number} pointer's y coordinate
|
477
|
+
*/
|
478
|
+
_translateObject: function (x, y) {
|
479
|
+
var target = this._currentTransform.target;
|
480
|
+
|
481
|
+
if (!target.get('lockMovementX')) {
|
482
|
+
target.set('left', x - this._currentTransform.offsetX);
|
483
|
+
}
|
484
|
+
if (!target.get('lockMovementY')) {
|
485
|
+
target.set('top', y - this._currentTransform.offsetY);
|
486
|
+
}
|
487
|
+
},
|
488
|
+
|
489
|
+
/**
|
490
|
+
* Scales object by invoking its scaleX/scaleY methods
|
491
|
+
* @method _scaleObject
|
492
|
+
* @param x {Number} pointer's x coordinate
|
493
|
+
* @param y {Number} pointer's y coordinate
|
494
|
+
* @param by {String} Either 'x' or 'y' - specifies dimension constraint by which to scale an object.
|
495
|
+
* When not provided, an object is scaled by both dimensions equally
|
496
|
+
*/
|
497
|
+
_scaleObject: function (x, y, by) {
|
498
|
+
var t = this._currentTransform,
|
499
|
+
offset = this._offset,
|
500
|
+
target = t.target;
|
501
|
+
|
502
|
+
var lockScalingX = target.get('lockScalingX'),
|
503
|
+
lockScalingY = target.get('lockScalingY');
|
504
|
+
|
505
|
+
if (lockScalingX && lockScalingY) return;
|
506
|
+
|
507
|
+
// Get the constraint point
|
508
|
+
var constraintPosition = target.translateToOriginPoint(target.getCenterPoint(), t.originX, t.originY);
|
509
|
+
var localMouse = target.toLocalPoint(new fabric.Point(x - offset.left, y - offset.top), t.originX, t.originY);
|
510
|
+
|
511
|
+
if (t.originX === 'right') {
|
512
|
+
localMouse.x *= -1;
|
513
|
+
}
|
514
|
+
else if (t.originX === 'center') {
|
515
|
+
localMouse.x *= t.mouseXSign * 2;
|
516
|
+
|
517
|
+
if (localMouse.x < 0) {
|
518
|
+
t.mouseXSign = -t.mouseXSign;
|
519
|
+
}
|
520
|
+
}
|
521
|
+
|
522
|
+
if (t.originY === 'bottom') {
|
523
|
+
localMouse.y *= -1;
|
524
|
+
}
|
525
|
+
else if (t.originY === 'center') {
|
526
|
+
localMouse.y *= t.mouseYSign * 2;
|
527
|
+
|
528
|
+
if (localMouse.y < 0) {
|
529
|
+
t.mouseYSign = -t.mouseYSign;
|
530
|
+
}
|
531
|
+
}
|
532
|
+
|
533
|
+
// Actually scale the object
|
534
|
+
var newScaleX = target.scaleX, newScaleY = target.scaleY;
|
535
|
+
if (by === 'equally' && !lockScalingX && !lockScalingY) {
|
536
|
+
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 */;
|
541
|
+
|
542
|
+
// 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
|
+
newScaleX = t.original.scaleX * dist/lastDist;
|
544
|
+
newScaleY = t.original.scaleY * dist/lastDist;
|
545
|
+
|
546
|
+
target.set('scaleX', newScaleX);
|
547
|
+
target.set('scaleY', newScaleY);
|
548
|
+
}
|
549
|
+
else if (!by) {
|
550
|
+
newScaleX = localMouse.x/(target.width+target.padding);
|
551
|
+
newScaleY = localMouse.y/(target.height+target.padding);
|
552
|
+
|
553
|
+
lockScalingX || target.set('scaleX', newScaleX);
|
554
|
+
lockScalingY || target.set('scaleY', newScaleY);
|
555
|
+
}
|
556
|
+
else if (by === 'x' && !target.get('lockUniScaling')) {
|
557
|
+
newScaleX = localMouse.x/(target.width+target.padding);
|
558
|
+
lockScalingX || target.set('scaleX', newScaleX);
|
559
|
+
}
|
560
|
+
else if (by === 'y' && !target.get('lockUniScaling')) {
|
561
|
+
newScaleY = localMouse.y/(target.height+target.padding);
|
562
|
+
lockScalingY || target.set('scaleY', newScaleY);
|
563
|
+
}
|
564
|
+
|
565
|
+
// Check if we flipped
|
566
|
+
if (newScaleX < 0)
|
567
|
+
{
|
568
|
+
if (t.originX === 'left')
|
569
|
+
t.originX = 'right';
|
570
|
+
else if (t.originX === 'right')
|
571
|
+
t.originX = 'left';
|
572
|
+
}
|
573
|
+
|
574
|
+
if (newScaleY < 0)
|
575
|
+
{
|
576
|
+
if (t.originY === 'top')
|
577
|
+
t.originY = 'bottom';
|
578
|
+
else if (t.originY === 'bottom')
|
579
|
+
t.originY = 'top';
|
580
|
+
}
|
581
|
+
|
582
|
+
// Make sure the constraints apply
|
583
|
+
target.setPositionByOrigin(constraintPosition, t.originX, t.originY);
|
584
|
+
},
|
585
|
+
|
586
|
+
/**
|
587
|
+
* Rotates object by invoking its rotate method
|
588
|
+
* @method _rotateObject
|
589
|
+
* @param x {Number} pointer's x coordinate
|
590
|
+
* @param y {Number} pointer's y coordinate
|
591
|
+
*/
|
592
|
+
_rotateObject: function (x, y) {
|
593
|
+
|
594
|
+
var t = this._currentTransform,
|
595
|
+
o = this._offset;
|
596
|
+
|
597
|
+
if (t.target.get('lockRotation')) return;
|
598
|
+
|
599
|
+
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);
|
601
|
+
|
602
|
+
t.target.angle = radiansToDegrees(curAngle - lastAngle + t.theta);
|
603
|
+
},
|
604
|
+
|
605
|
+
/**
|
606
|
+
* @method _setCursor
|
607
|
+
*/
|
608
|
+
_setCursor: function (value) {
|
609
|
+
this.upperCanvasEl.style.cursor = value;
|
610
|
+
},
|
611
|
+
|
612
|
+
/**
|
613
|
+
* @private
|
614
|
+
* @method _resetObjectTransform:
|
615
|
+
*/
|
616
|
+
_resetObjectTransform: function (target) {
|
617
|
+
target.scaleX = 1;
|
618
|
+
target.scaleY = 1;
|
619
|
+
target.setAngle(0);
|
620
|
+
},
|
621
|
+
|
622
|
+
/**
|
623
|
+
* @method _drawSelection
|
624
|
+
* @private
|
625
|
+
*/
|
626
|
+
_drawSelection: function () {
|
627
|
+
var ctx = this.contextTop,
|
628
|
+
groupSelector = this._groupSelector,
|
629
|
+
left = groupSelector.left,
|
630
|
+
top = groupSelector.top,
|
631
|
+
aleft = abs(left),
|
632
|
+
atop = abs(top);
|
633
|
+
|
634
|
+
ctx.fillStyle = this.selectionColor;
|
635
|
+
|
636
|
+
ctx.fillRect(
|
637
|
+
groupSelector.ex - ((left > 0) ? 0 : -left),
|
638
|
+
groupSelector.ey - ((top > 0) ? 0 : -top),
|
639
|
+
aleft,
|
640
|
+
atop
|
641
|
+
);
|
642
|
+
|
643
|
+
ctx.lineWidth = this.selectionLineWidth;
|
644
|
+
ctx.strokeStyle = this.selectionBorderColor;
|
645
|
+
|
646
|
+
// selection border
|
647
|
+
if (this.selectionDashArray.length > 1) {
|
648
|
+
|
649
|
+
var px = groupSelector.ex + STROKE_OFFSET - ((left > 0) ? 0: aleft);
|
650
|
+
var py = groupSelector.ey + STROKE_OFFSET - ((top > 0) ? 0: atop);
|
651
|
+
|
652
|
+
ctx.beginPath();
|
653
|
+
|
654
|
+
fabric.util.drawDashedLine(ctx, px, py, px+aleft, py, this.selectionDashArray);
|
655
|
+
fabric.util.drawDashedLine(ctx, px, py+atop-1, px+aleft, py+atop-1, this.selectionDashArray);
|
656
|
+
fabric.util.drawDashedLine(ctx, px, py, px, py+atop, this.selectionDashArray);
|
657
|
+
fabric.util.drawDashedLine(ctx, px+aleft-1, py, px+aleft-1, py+atop, this.selectionDashArray);
|
658
|
+
|
659
|
+
ctx.closePath();
|
660
|
+
ctx.stroke();
|
661
|
+
}
|
662
|
+
else {
|
663
|
+
ctx.strokeRect(
|
664
|
+
groupSelector.ex + STROKE_OFFSET - ((left > 0) ? 0 : aleft),
|
665
|
+
groupSelector.ey + STROKE_OFFSET - ((top > 0) ? 0 : atop),
|
666
|
+
aleft,
|
667
|
+
atop
|
668
|
+
);
|
669
|
+
}
|
670
|
+
},
|
671
|
+
|
672
|
+
/**
|
673
|
+
* @private
|
674
|
+
* @method _findSelectedObjects
|
675
|
+
*/
|
676
|
+
_findSelectedObjects: function (e) {
|
677
|
+
var group = [ ],
|
678
|
+
x1 = this._groupSelector.ex,
|
679
|
+
y1 = this._groupSelector.ey,
|
680
|
+
x2 = x1 + this._groupSelector.left,
|
681
|
+
y2 = y1 + this._groupSelector.top,
|
682
|
+
currentObject,
|
683
|
+
selectionX1Y1 = new fabric.Point(min(x1, x2), min(y1, y2)),
|
684
|
+
selectionX2Y2 = new fabric.Point(max(x1, x2), max(y1, y2));
|
685
|
+
|
686
|
+
for (var i = 0, len = this._objects.length; i < len; ++i) {
|
687
|
+
currentObject = this._objects[i];
|
688
|
+
|
689
|
+
if (!currentObject) continue;
|
690
|
+
|
691
|
+
if (currentObject.intersectsWithRect(selectionX1Y1, selectionX2Y2) ||
|
692
|
+
currentObject.isContainedWithinRect(selectionX1Y1, selectionX2Y2)) {
|
693
|
+
|
694
|
+
if (this.selection && currentObject.selectable) {
|
695
|
+
currentObject.setActive(true);
|
696
|
+
group.push(currentObject);
|
697
|
+
}
|
698
|
+
}
|
699
|
+
}
|
700
|
+
|
701
|
+
// do not create group for 1 element only
|
702
|
+
if (group.length === 1) {
|
703
|
+
this.setActiveObject(group[0], e);
|
704
|
+
}
|
705
|
+
else if (group.length > 1) {
|
706
|
+
group = new fabric.Group(group);
|
707
|
+
this.setActiveGroup(group);
|
708
|
+
group.saveCoords();
|
709
|
+
this.fire('selection:created', { target: group });
|
710
|
+
}
|
711
|
+
|
712
|
+
this.renderAll();
|
713
|
+
},
|
714
|
+
|
715
|
+
/**
|
716
|
+
* Method that determines what object we are clicking on
|
717
|
+
* @method findTarget
|
718
|
+
* @param {Event} e mouse event
|
719
|
+
* @param {Boolean} skipGroup when true, group is skipped and only objects are traversed through
|
720
|
+
*/
|
721
|
+
findTarget: function (e, skipGroup) {
|
722
|
+
|
723
|
+
var target,
|
724
|
+
pointer = this.getPointer(e);
|
725
|
+
|
726
|
+
if (this.controlsAboveOverlay &&
|
727
|
+
this.lastRenderedObjectWithControlsAboveOverlay &&
|
728
|
+
this.containsPoint(e, this.lastRenderedObjectWithControlsAboveOverlay) &&
|
729
|
+
this.lastRenderedObjectWithControlsAboveOverlay._findTargetCorner(e, this._offset)) {
|
730
|
+
target = this.lastRenderedObjectWithControlsAboveOverlay;
|
731
|
+
return target;
|
732
|
+
}
|
733
|
+
|
734
|
+
// first check current group (if one exists)
|
735
|
+
var activeGroup = this.getActiveGroup();
|
736
|
+
if (activeGroup && !skipGroup && this.containsPoint(e, activeGroup)) {
|
737
|
+
target = activeGroup;
|
738
|
+
return target;
|
739
|
+
}
|
740
|
+
|
741
|
+
// then check all of the objects on canvas
|
742
|
+
// Cache all targets where their bounding box contains point.
|
743
|
+
var possibleTargets = [];
|
744
|
+
for (var i = this._objects.length; i--; ) {
|
745
|
+
if (this._objects[i] && this.containsPoint(e, this._objects[i])) {
|
746
|
+
if (this.perPixelTargetFind || this._objects[i].perPixelTargetFind) {
|
747
|
+
possibleTargets[possibleTargets.length] = this._objects[i];
|
748
|
+
}
|
749
|
+
else {
|
750
|
+
target = this._objects[i];
|
751
|
+
this.relatedTarget = target;
|
752
|
+
break;
|
753
|
+
}
|
754
|
+
}
|
755
|
+
}
|
756
|
+
for (var j = 0, len = possibleTargets.length; j < len; j++) {
|
757
|
+
pointer = this.getPointer(e);
|
758
|
+
var isTransparent = this._isTargetTransparent(possibleTargets[j], pointer.x, pointer.y);
|
759
|
+
if (!isTransparent) {
|
760
|
+
target = possibleTargets[j];
|
761
|
+
this.relatedTarget = target;
|
762
|
+
break;
|
763
|
+
}
|
764
|
+
}
|
765
|
+
if (target && target.selectable) {
|
766
|
+
return target;
|
767
|
+
}
|
768
|
+
},
|
769
|
+
|
770
|
+
/**
|
771
|
+
* Returns pointer coordinates relative to canvas.
|
772
|
+
* @method getPointer
|
773
|
+
* @param {Event} e
|
774
|
+
* @return {Object} object with "x" and "y" number values
|
775
|
+
*/
|
776
|
+
getPointer: function (e) {
|
777
|
+
var pointer = getPointer(e, this.upperCanvasEl);
|
778
|
+
return {
|
779
|
+
x: pointer.x - this._offset.left,
|
780
|
+
y: pointer.y - this._offset.top
|
781
|
+
};
|
782
|
+
},
|
783
|
+
|
784
|
+
/**
|
785
|
+
* @private
|
786
|
+
* @method _createUpperCanvas
|
787
|
+
* @param {HTMLElement|String} canvasEl Canvas element
|
788
|
+
* @throws {CANVAS_INIT_ERROR} If canvas can not be initialized
|
789
|
+
*/
|
790
|
+
_createUpperCanvas: function () {
|
791
|
+
this.upperCanvasEl = this._createCanvasElement();
|
792
|
+
this.upperCanvasEl.className = 'upper-canvas';
|
793
|
+
|
794
|
+
this.wrapperEl.appendChild(this.upperCanvasEl);
|
795
|
+
|
796
|
+
this._applyCanvasStyle(this.upperCanvasEl);
|
797
|
+
this.contextTop = this.upperCanvasEl.getContext('2d');
|
798
|
+
},
|
799
|
+
|
800
|
+
/**
|
801
|
+
* @private
|
802
|
+
* @method _createCacheCanvas
|
803
|
+
*/
|
804
|
+
_createCacheCanvas: function () {
|
805
|
+
this.cacheCanvasEl = this._createCanvasElement();
|
806
|
+
this.cacheCanvasEl.setAttribute('width', this.width);
|
807
|
+
this.cacheCanvasEl.setAttribute('height', this.height);
|
808
|
+
this.contextCache = this.cacheCanvasEl.getContext('2d');
|
809
|
+
},
|
810
|
+
|
811
|
+
/**
|
812
|
+
* @private
|
813
|
+
* @method _initWrapperElement
|
814
|
+
* @param {Number} width
|
815
|
+
* @param {Number} height
|
816
|
+
*/
|
817
|
+
_initWrapperElement: function () {
|
818
|
+
this.wrapperEl = fabric.util.wrapElement(this.lowerCanvasEl, 'div', {
|
819
|
+
'class': this.containerClass
|
820
|
+
});
|
821
|
+
fabric.util.setStyle(this.wrapperEl, {
|
822
|
+
width: this.getWidth() + 'px',
|
823
|
+
height: this.getHeight() + 'px',
|
824
|
+
position: 'relative'
|
825
|
+
});
|
826
|
+
fabric.util.makeElementUnselectable(this.wrapperEl);
|
827
|
+
},
|
828
|
+
|
829
|
+
/**
|
830
|
+
* @private
|
831
|
+
* @method _applyCanvasStyle
|
832
|
+
* @param {Element} element
|
833
|
+
*/
|
834
|
+
_applyCanvasStyle: function (element) {
|
835
|
+
var width = this.getWidth() || element.width,
|
836
|
+
height = this.getHeight() || element.height;
|
837
|
+
|
838
|
+
fabric.util.setStyle(element, {
|
839
|
+
position: 'absolute',
|
840
|
+
width: width + 'px',
|
841
|
+
height: height + 'px',
|
842
|
+
left: 0,
|
843
|
+
top: 0
|
844
|
+
});
|
845
|
+
element.width = width;
|
846
|
+
element.height = height;
|
847
|
+
fabric.util.makeElementUnselectable(element);
|
848
|
+
},
|
849
|
+
|
850
|
+
/**
|
851
|
+
* Returns context of canvas where object selection is drawn
|
852
|
+
* @method getSelectionContext
|
853
|
+
* @return {CanvasRenderingContext2D}
|
854
|
+
*/
|
855
|
+
getSelectionContext: function() {
|
856
|
+
return this.contextTop;
|
857
|
+
},
|
858
|
+
|
859
|
+
/**
|
860
|
+
* Returns <canvas> element on which object selection is drawn
|
861
|
+
* @method getSelectionElement
|
862
|
+
* @return {HTMLCanvasElement}
|
863
|
+
*/
|
864
|
+
getSelectionElement: function () {
|
865
|
+
return this.upperCanvasEl;
|
866
|
+
},
|
867
|
+
|
868
|
+
/**
|
869
|
+
* Sets given object as active
|
870
|
+
* @method setActiveObject
|
871
|
+
* @param object {fabric.Object} Object to set as an active one
|
872
|
+
* @return {fabric.Canvas} thisArg
|
873
|
+
* @chainable
|
874
|
+
*/
|
875
|
+
setActiveObject: function (object, e) {
|
876
|
+
if (this._activeObject) {
|
877
|
+
this._activeObject.setActive(false);
|
878
|
+
}
|
879
|
+
this._activeObject = object;
|
880
|
+
object.setActive(true);
|
881
|
+
|
882
|
+
this.renderAll();
|
883
|
+
|
884
|
+
this.fire('object:selected', { target: object, e: e });
|
885
|
+
object.fire('selected', { e: e });
|
886
|
+
return this;
|
887
|
+
},
|
888
|
+
|
889
|
+
/**
|
890
|
+
* Returns currently active object
|
891
|
+
* @method getActiveObject
|
892
|
+
* @return {fabric.Object} active object
|
893
|
+
*/
|
894
|
+
getActiveObject: function () {
|
895
|
+
return this._activeObject;
|
896
|
+
},
|
897
|
+
|
898
|
+
/**
|
899
|
+
* Discards currently active object
|
900
|
+
* @method discardActiveObject
|
901
|
+
* @return {fabric.Canvas} thisArg
|
902
|
+
* @chainable
|
903
|
+
*/
|
904
|
+
discardActiveObject: function () {
|
905
|
+
if (this._activeObject) {
|
906
|
+
this._activeObject.setActive(false);
|
907
|
+
}
|
908
|
+
this._activeObject = null;
|
909
|
+
return this;
|
910
|
+
},
|
911
|
+
|
912
|
+
/**
|
913
|
+
* Sets active group to a speicified one
|
914
|
+
* @method setActiveGroup
|
915
|
+
* @param {fabric.Group} group Group to set as a current one
|
916
|
+
* @return {fabric.Canvas} thisArg
|
917
|
+
* @chainable
|
918
|
+
*/
|
919
|
+
setActiveGroup: function (group) {
|
920
|
+
this._activeGroup = group;
|
921
|
+
if (group) {
|
922
|
+
group.canvas = this;
|
923
|
+
group.setActive(true);
|
924
|
+
}
|
925
|
+
return this;
|
926
|
+
},
|
927
|
+
|
928
|
+
/**
|
929
|
+
* Returns currently active group
|
930
|
+
* @method getActiveGroup
|
931
|
+
* @return {fabric.Group} Current group
|
932
|
+
*/
|
933
|
+
getActiveGroup: function () {
|
934
|
+
return this._activeGroup;
|
935
|
+
},
|
936
|
+
|
937
|
+
/**
|
938
|
+
* Removes currently active group
|
939
|
+
* @method discardActiveGroup
|
940
|
+
* @return {fabric.Canvas} thisArg
|
941
|
+
*/
|
942
|
+
discardActiveGroup: function () {
|
943
|
+
var g = this.getActiveGroup();
|
944
|
+
if (g) {
|
945
|
+
g.destroy();
|
946
|
+
}
|
947
|
+
return this.setActiveGroup(null);
|
948
|
+
},
|
949
|
+
|
950
|
+
/**
|
951
|
+
* Deactivates all objects by calling their setActive(false)
|
952
|
+
* @method deactivateAll
|
953
|
+
* @return {fabric.Canvas} thisArg
|
954
|
+
*/
|
955
|
+
deactivateAll: function () {
|
956
|
+
var allObjects = this.getObjects(),
|
957
|
+
i = 0,
|
958
|
+
len = allObjects.length;
|
959
|
+
for ( ; i < len; i++) {
|
960
|
+
allObjects[i].setActive(false);
|
961
|
+
}
|
962
|
+
this.discardActiveGroup();
|
963
|
+
this.discardActiveObject();
|
964
|
+
return this;
|
965
|
+
},
|
966
|
+
|
967
|
+
/**
|
968
|
+
* Deactivates all objects and dispatches appropriate events
|
969
|
+
* @method deactivateAllWithDispatch
|
970
|
+
* @return {fabric.Canvas} thisArg
|
971
|
+
*/
|
972
|
+
deactivateAllWithDispatch: function () {
|
973
|
+
var activeObject = this.getActiveGroup() || this.getActiveObject();
|
974
|
+
if (activeObject) {
|
975
|
+
this.fire('before:selection:cleared', { target: activeObject });
|
976
|
+
}
|
977
|
+
this.deactivateAll();
|
978
|
+
if (activeObject) {
|
979
|
+
this.fire('selection:cleared');
|
980
|
+
}
|
981
|
+
return this;
|
982
|
+
}
|
983
|
+
};
|
984
|
+
|
985
|
+
fabric.Canvas.prototype.toString = fabric.StaticCanvas.prototype.toString;
|
986
|
+
extend(fabric.Canvas.prototype, InteractiveMethods);
|
987
|
+
|
988
|
+
// iterating manually to workaround Opera's bug
|
989
|
+
// where "prototype" property is enumerable and overrides existing prototype
|
990
|
+
for (var prop in fabric.StaticCanvas) {
|
991
|
+
if (prop !== 'prototype') {
|
992
|
+
fabric.Canvas[prop] = fabric.StaticCanvas[prop];
|
993
|
+
}
|
994
|
+
}
|
995
|
+
|
996
|
+
if (fabric.isTouchSupported) {
|
997
|
+
fabric.Canvas.prototype._setCursorFromEvent = function() { };
|
998
|
+
}
|
999
|
+
|
1000
|
+
/**
|
1001
|
+
* @class fabric.Element
|
1002
|
+
* @alias fabric.Canvas
|
1003
|
+
* @deprecated Use {@link fabric.Canvas} instead.
|
1004
|
+
* @constructor
|
1005
|
+
*/
|
1006
|
+
fabric.Element = fabric.Canvas;
|
1007
|
+
})();
|