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.
Files changed (76) hide show
  1. data/CHANGELOG.md +4 -0
  2. data/README.md +1 -1
  3. data/lib/fabric/rails/version.rb +2 -2
  4. data/vendor/assets/javascripts/cufon.js +1226 -0
  5. data/vendor/assets/javascripts/event.js +20 -20
  6. data/vendor/assets/javascripts/excanvas.js +1464 -0
  7. data/vendor/assets/javascripts/fabric.js +56 -33
  8. data/vendor/assets/javascripts/fabric/HEADER.js +2 -4
  9. data/vendor/assets/javascripts/fabric/brushes/base_brush.class.js +96 -0
  10. data/vendor/assets/javascripts/fabric/brushes/circle_brush.class.js +99 -0
  11. data/vendor/assets/javascripts/fabric/brushes/pattern_brush.class.js +55 -0
  12. data/vendor/assets/javascripts/fabric/{freedrawing.class.js → brushes/pencil_brush.class.js} +73 -65
  13. data/vendor/assets/javascripts/fabric/brushes/spray_brush.class.js +157 -0
  14. data/vendor/assets/javascripts/fabric/canvas.class.js +154 -135
  15. data/vendor/assets/javascripts/fabric/color.class.js +195 -29
  16. data/vendor/assets/javascripts/fabric/filters/brightness_filter.class.js +70 -0
  17. data/vendor/assets/javascripts/fabric/filters/convolute_filter.class.js +122 -0
  18. data/vendor/assets/javascripts/fabric/filters/gradienttransparency_filter.class.js +69 -0
  19. data/vendor/assets/javascripts/fabric/filters/grayscale_filter.class.js +61 -0
  20. data/vendor/assets/javascripts/fabric/filters/invert_filter.class.js +57 -0
  21. data/vendor/assets/javascripts/fabric/filters/noise_filter.class.js +73 -0
  22. data/vendor/assets/javascripts/fabric/filters/pixelate_filter.class.js +98 -0
  23. data/vendor/assets/javascripts/fabric/filters/removewhite_filter.class.js +86 -0
  24. data/vendor/assets/javascripts/fabric/filters/sepia2_filter.class.js +61 -0
  25. data/vendor/assets/javascripts/fabric/filters/sepia_filter.class.js +58 -0
  26. data/vendor/assets/javascripts/fabric/filters/tint_filter.class.js +80 -0
  27. data/vendor/assets/javascripts/fabric/gradient.class.js +232 -80
  28. data/vendor/assets/javascripts/fabric/intersection.class.js +10 -28
  29. data/vendor/assets/javascripts/fabric/log.js +0 -2
  30. data/vendor/assets/javascripts/fabric/{canvas_animation.mixin.js → mixins/canvas_animation.mixin.js} +3 -6
  31. data/vendor/assets/javascripts/fabric/mixins/canvas_dataurl_exporter.mixin.js +137 -0
  32. data/vendor/assets/javascripts/fabric/{canvas_events.mixin.js → mixins/canvas_events.mixin.js} +97 -144
  33. data/vendor/assets/javascripts/fabric/{canvas_gestures.mixin.js → mixins/canvas_gestures.mixin.js} +4 -8
  34. data/vendor/assets/javascripts/fabric/{canvas_serialization.mixin.js → mixins/canvas_serialization.mixin.js} +19 -14
  35. data/vendor/assets/javascripts/fabric/mixins/collection.mixin.js +137 -0
  36. data/vendor/assets/javascripts/fabric/{object_geometry.mixin.js → mixins/object_geometry.mixin.js} +130 -47
  37. data/vendor/assets/javascripts/fabric/{object_interactivity.mixin.js → mixins/object_interactivity.mixin.js} +21 -102
  38. data/vendor/assets/javascripts/fabric/{object_origin.mixin.js → mixins/object_origin.mixin.js} +36 -26
  39. data/vendor/assets/javascripts/fabric/{object_straightening.mixin.js → mixins/object_straightening.mixin.js} +4 -9
  40. data/vendor/assets/javascripts/fabric/{observable.mixin.js → mixins/observable.mixin.js} +27 -35
  41. data/vendor/assets/javascripts/fabric/mixins/stateful.mixin.js +45 -0
  42. data/vendor/assets/javascripts/fabric/node.js +62 -26
  43. data/vendor/assets/javascripts/fabric/parser.js +181 -58
  44. data/vendor/assets/javascripts/fabric/pattern.class.js +43 -14
  45. data/vendor/assets/javascripts/fabric/point.class.js +4 -43
  46. data/vendor/assets/javascripts/fabric/shadow.class.js +19 -19
  47. data/vendor/assets/javascripts/fabric/{circle.class.js → shapes/circle.class.js} +32 -29
  48. data/vendor/assets/javascripts/fabric/{ellipse.class.js → shapes/ellipse.class.js} +45 -27
  49. data/vendor/assets/javascripts/fabric/{group.class.js → shapes/group.class.js} +67 -169
  50. data/vendor/assets/javascripts/fabric/{image.class.js → shapes/image.class.js} +134 -72
  51. data/vendor/assets/javascripts/fabric/{line.class.js → shapes/line.class.js} +67 -36
  52. data/vendor/assets/javascripts/fabric/{object.class.js → shapes/object.class.js} +394 -252
  53. data/vendor/assets/javascripts/fabric/{path.class.js → shapes/path.class.js} +89 -174
  54. data/vendor/assets/javascripts/fabric/{path_group.class.js → shapes/path_group.class.js} +12 -18
  55. data/vendor/assets/javascripts/fabric/{polygon.class.js → shapes/polygon.class.js} +64 -38
  56. data/vendor/assets/javascripts/fabric/{polyline.class.js → shapes/polyline.class.js} +64 -39
  57. data/vendor/assets/javascripts/fabric/{rect.class.js → shapes/rect.class.js} +78 -112
  58. data/vendor/assets/javascripts/fabric/{text.class.js → shapes/text.class.js} +264 -270
  59. data/vendor/assets/javascripts/fabric/shapes/text.cufon.js +79 -0
  60. data/vendor/assets/javascripts/fabric/{triangle.class.js → shapes/triangle.class.js} +46 -26
  61. data/vendor/assets/javascripts/fabric/static_canvas.class.js +134 -358
  62. data/vendor/assets/javascripts/fabric/util/anim_ease.js +2 -31
  63. data/vendor/assets/javascripts/fabric/util/dom_event.js +21 -7
  64. data/vendor/assets/javascripts/fabric/util/dom_misc.js +49 -39
  65. data/vendor/assets/javascripts/fabric/util/dom_request.js +1 -2
  66. data/vendor/assets/javascripts/fabric/util/dom_style.js +1 -2
  67. data/vendor/assets/javascripts/fabric/util/lang_array.js +19 -13
  68. data/vendor/assets/javascripts/fabric/util/lang_class.js +1 -2
  69. data/vendor/assets/javascripts/fabric/util/lang_function.js +3 -1
  70. data/vendor/assets/javascripts/fabric/util/lang_object.js +5 -5
  71. data/vendor/assets/javascripts/fabric/util/lang_string.js +7 -5
  72. data/vendor/assets/javascripts/fabric/util/misc.js +207 -42
  73. metadata +47 -29
  74. data/vendor/assets/javascripts/fabric/image_filters.js +0 -809
  75. data/vendor/assets/javascripts/fabric/scout.js +0 -45
  76. data/vendor/assets/javascripts/fabric/stateful.js +0 -88
@@ -6,298 +6,366 @@
6
6
  extend = fabric.util.object.extend,
7
7
  toFixed = fabric.util.toFixed,
8
8
  capitalize = fabric.util.string.capitalize,
9
- degreesToRadians = fabric.util.degreesToRadians;
9
+ degreesToRadians = fabric.util.degreesToRadians,
10
+ supportsLineDash = fabric.StaticCanvas.supports('setLineDash');
10
11
 
11
12
  if (fabric.Object) {
12
13
  return;
13
14
  }
14
15
 
15
- var Image = global.Image;
16
- try {
17
- var NodeImage = (typeof require !== 'undefined') && require('canvas').Image;
18
- if (NodeImage) {
19
- Image = NodeImage;
20
- }
21
- }
22
- catch(err) {
23
- fabric.log(err);
24
- }
25
-
26
16
  /**
27
17
  * Root object class from which all 2d shape classes inherit from
28
- * @class Object
29
- * @memberOf fabric
18
+ * @class fabric.Object
30
19
  */
31
- fabric.Object = fabric.util.createClass(/** @scope fabric.Object.prototype */ {
20
+ fabric.Object = fabric.util.createClass(/** @lends fabric.Object.prototype */ {
32
21
 
33
22
  /**
34
23
  * Type of an object (rect, circle, path, etc.)
35
- * @property
36
24
  * @type String
25
+ * @default
37
26
  */
38
27
  type: 'object',
39
28
 
40
29
  /**
41
30
  * Horizontal origin of transformation of an object (one of "left", "right", "center")
42
- * @property
43
31
  * @type String
32
+ * @default
44
33
  */
45
34
  originX: 'center',
46
35
 
47
36
  /**
48
37
  * Vertical origin of transformation of an object (one of "top", "bottom", "center")
49
- * @property
50
38
  * @type String
39
+ * @default
51
40
  */
52
41
  originY: 'center',
53
42
 
54
43
  /**
55
- * Top position of an object
56
- * @property
44
+ * Top position of an object. Note that by default it's relative to object center. You can change this by setting originY={top/center/bottom}
57
45
  * @type Number
46
+ * @default
58
47
  */
59
48
  top: 0,
60
49
 
61
50
  /**
62
- * Left position of an object
63
- * @property
51
+ * Left position of an object. Note that by default it's relative to object center. You can change this by setting originX={left/center/right}
64
52
  * @type Number
53
+ * @default
65
54
  */
66
55
  left: 0,
67
56
 
68
57
  /**
69
58
  * Object width
70
- * @property
71
59
  * @type Number
60
+ * @default
72
61
  */
73
62
  width: 0,
74
63
 
75
64
  /**
76
65
  * Object height
77
- * @property
78
66
  * @type Number
67
+ * @default
79
68
  */
80
69
  height: 0,
81
70
 
82
71
  /**
83
72
  * Object scale factor (horizontal)
84
- * @property
85
73
  * @type Number
74
+ * @default
86
75
  */
87
76
  scaleX: 1,
88
77
 
89
78
  /**
90
79
  * Object scale factor (vertical)
91
- * @property
92
80
  * @type Number
81
+ * @default
93
82
  */
94
83
  scaleY: 1,
95
84
 
96
85
  /**
97
86
  * When true, an object is rendered as flipped horizontally
98
- * @property
99
87
  * @type Boolean
88
+ * @default
100
89
  */
101
90
  flipX: false,
102
91
 
103
92
  /**
104
93
  * When true, an object is rendered as flipped vertically
105
- * @property
106
94
  * @type Boolean
95
+ * @default
107
96
  */
108
97
  flipY: false,
109
98
 
110
99
  /**
111
100
  * Opacity of an object
112
- * @property
113
101
  * @type Number
102
+ * @default
114
103
  */
115
104
  opacity: 1,
116
105
 
117
106
  /**
118
107
  * Angle of rotation of an object (in degrees)
119
- * @property
120
108
  * @type Number
109
+ * @default
121
110
  */
122
111
  angle: 0,
123
112
 
124
113
  /**
125
- * Size of object's corners (in pixels)
126
- * @property
114
+ * Size of object's controlling corners (in pixels)
127
115
  * @type Number
116
+ * @default
128
117
  */
129
118
  cornerSize: 12,
130
119
 
131
120
  /**
132
- * When true, object's corners are rendered as transparent inside (i.e. stroke instead of fill)
133
- * @property
121
+ * When true, object's controlling corners are rendered as transparent inside (i.e. stroke instead of fill)
134
122
  * @type Boolean
123
+ * @default
135
124
  */
136
125
  transparentCorners: true,
137
126
 
138
127
  /**
139
- * Padding between object and its borders (in pixels)
140
- * @property
128
+ * Padding between object and its controlling borders (in pixels)
141
129
  * @type Number
130
+ * @default
142
131
  */
143
132
  padding: 0,
144
133
 
145
134
  /**
146
- * Border color of an object (when it's active)
147
- * @property
135
+ * Color of controlling borders of an object (when it's active)
148
136
  * @type String
137
+ * @default
149
138
  */
150
139
  borderColor: 'rgba(102,153,255,0.75)',
151
140
 
152
141
  /**
153
- * Corner color of an object (when it's active)
154
- * @property
142
+ * Color of controlling corners of an object (when it's active)
155
143
  * @type String
144
+ * @default
156
145
  */
157
146
  cornerColor: 'rgba(102,153,255,0.5)',
158
147
 
148
+ /**
149
+ * When true, this object will use center point as the origin of transformation
150
+ * when being resized via the controls
151
+ * @type Boolean
152
+ */
153
+ centerTransform: false,
154
+
159
155
  /**
160
156
  * Color of object's fill
161
- * @property
162
157
  * @type String
158
+ * @default
163
159
  */
164
160
  fill: 'rgb(0,0,0)',
165
161
 
166
162
  /**
167
163
  * Fill rule used to fill an object
168
- * @property
169
164
  * @type String
165
+ * @default
170
166
  */
171
167
  fillRule: 'source-over',
172
168
 
173
169
  /**
174
170
  * Overlay fill (takes precedence over fill value)
175
- * @property
176
171
  * @type String
172
+ * @default
177
173
  */
178
174
  overlayFill: null,
179
175
 
180
176
  /**
181
- * When `true`, an object is rendered via stroke and this property specifies its color
182
- * @property
177
+ * When defined, an object is rendered via stroke and this property specifies its color
183
178
  * @type String
179
+ * @default
184
180
  */
185
181
  stroke: null,
186
182
 
187
183
  /**
188
184
  * Width of a stroke used to render this object
189
- * @property
190
185
  * @type Number
186
+ * @default
191
187
  */
192
188
  strokeWidth: 1,
193
189
 
194
190
  /**
195
- * Array specifying dash pattern of an object's stroke
196
- * @property
191
+ * Array specifying dash pattern of an object's stroke (stroke must be defined)
197
192
  * @type Array
198
193
  */
199
194
  strokeDashArray: null,
200
195
 
196
+ /**
197
+ * Line endings style of an object's stroke (one of "butt", "round", "square")
198
+ * @type String
199
+ * @default
200
+ */
201
+ strokeLineCap: 'butt',
202
+
203
+ /**
204
+ * Corner style of an object's stroke (one of "bevil", "round", "miter")
205
+ * @type String
206
+ * @default
207
+ */
208
+ strokeLineJoin: 'miter',
209
+
210
+ /**
211
+ * Maximum miter length (used for strokeLineJoin = "miter") of an object's stroke
212
+ * @type Number
213
+ * @default
214
+ */
215
+ strokeMiterLimit: 10,
216
+
201
217
  /**
202
218
  * Shadow object representing shadow of this shape
203
- * @property
204
219
  * @type fabric.Shadow
205
220
  */
206
221
  shadow: null,
207
222
 
208
223
  /**
209
- * Border opacity when object is active and moving
210
- * @property
224
+ * Opacity of object's controlling borders when object is active and moving
211
225
  * @type Number
226
+ * @default
212
227
  */
213
228
  borderOpacityWhenMoving: 0.4,
214
229
 
215
230
  /**
216
- * Border scale factor
217
- * @property
231
+ * Scale factor of object's controlling borders
218
232
  * @type Number
233
+ * @default
219
234
  */
220
235
  borderScaleFactor: 1,
221
236
 
222
237
  /**
223
238
  * Transform matrix (similar to SVG's transform matrix)
224
- * @property
225
239
  * @type Array
226
240
  */
227
241
  transformMatrix: null,
228
242
 
229
243
  /**
230
244
  * Minimum allowed scale value of an object
231
- * @property
232
245
  * @type Number
246
+ * @default
233
247
  */
234
248
  minScaleLimit: 0.01,
235
249
 
236
250
  /**
237
251
  * When set to `false`, an object can not be selected for modification (using either point-click-based or group-based selection)
238
- * @property
239
252
  * @type Boolean
253
+ * @default
240
254
  */
241
255
  selectable: true,
242
256
 
257
+ /**
258
+ * When set to `false`, an object is not rendered on canvas
259
+ * @type Boolean
260
+ * @default
261
+ */
262
+ visible: true,
263
+
243
264
  /**
244
265
  * When set to `false`, object's controls are not displayed and can not be used to manipulate object
245
- * @property
246
266
  * @type Boolean
267
+ * @default
247
268
  */
248
269
  hasControls: true,
249
270
 
250
271
  /**
251
- * When set to `false`, object's borders are not rendered
252
- * @property
272
+ * When set to `false`, object's controlling borders are not rendered
253
273
  * @type Boolean
274
+ * @default
254
275
  */
255
276
  hasBorders: true,
256
277
 
257
278
  /**
258
- * When set to `false`, object's rotating point will not be visible or selectable
259
- * @property
279
+ * When set to `false`, object's controlling rotating point will not be visible or selectable
260
280
  * @type Boolean
281
+ * @default
261
282
  */
262
283
  hasRotatingPoint: true,
263
284
 
264
285
  /**
265
- * Offset for object's rotating point (when enabled via `hasRotatingPoint`)
266
- * @property
286
+ * Offset for object's controlling rotating point (when enabled via `hasRotatingPoint`)
267
287
  * @type Number
288
+ * @default
268
289
  */
269
290
  rotatingPointOffset: 40,
270
291
 
271
292
  /**
272
293
  * When set to `true`, objects are "found" on canvas on per-pixel basis rather than according to bounding box
273
- * @property
274
294
  * @type Boolean
295
+ * @default
275
296
  */
276
297
  perPixelTargetFind: false,
277
298
 
278
299
  /**
279
300
  * When `false`, default object's values are not included in its serialization
280
- * @property
281
301
  * @type Boolean
302
+ * @default
282
303
  */
283
304
  includeDefaultValues: true,
284
305
 
285
306
  /**
286
- * List of properties to consider when checking if state of an object is changed (fabric.Object#hasStateChanged);
307
+ * Function that determines clipping of an object (context is passed as a first argument)
308
+ * @type Function
309
+ */
310
+ clipTo: null,
311
+
312
+ /**
313
+ * When `true`, object horizontal movement is locked
314
+ * @type Boolean
315
+ * @default
316
+ */
317
+ lockMovementX: false,
318
+
319
+ /**
320
+ * When `true`, object vertical movement is locked
321
+ * @type Boolean
322
+ * @default
323
+ */
324
+ lockMovementY: false,
325
+
326
+ /**
327
+ * When `true`, object rotation is locked
328
+ * @type Boolean
329
+ * @default
330
+ */
331
+ lockRotation: false,
332
+
333
+ /**
334
+ * When `true`, object horizontal scaling is locked
335
+ * @type Boolean
336
+ * @default
337
+ */
338
+ lockScalingX: false,
339
+
340
+ /**
341
+ * When `true`, object vertical scaling is locked
342
+ * @type Boolean
343
+ * @default
344
+ */
345
+ lockScalingY: false,
346
+
347
+ /**
348
+ * When `true`, object non-uniform scaling is locked
349
+ * @type Boolean
350
+ * @default
351
+ */
352
+ lockUniScaling: false,
353
+
354
+ /**
355
+ * List of properties to consider when checking if state
356
+ * of an object is changed (fabric.Object#hasStateChanged)
287
357
  * as well as for history (undo/redo) purposes
288
- * @property
289
358
  * @type Array
290
359
  */
291
360
  stateProperties: (
292
361
  'top left width height scaleX scaleY flipX flipY ' +
293
362
  'angle opacity cornerSize fill overlayFill originX originY ' +
294
363
  'stroke strokeWidth strokeDashArray fillRule ' +
295
- 'borderScaleFactor transformMatrix selectable shadow'
364
+ 'borderScaleFactor transformMatrix selectable shadow visible'
296
365
  ).split(' '),
297
366
 
298
367
  /**
299
368
  * Constructor
300
- * @method initialize
301
369
  * @param {Object} [options] Options object
302
370
  */
303
371
  initialize: function(options) {
@@ -308,7 +376,6 @@
308
376
 
309
377
  /**
310
378
  * @private
311
- * @method _initGradient
312
379
  */
313
380
  _initGradient: function(options) {
314
381
  if (options.fill && options.fill.colorStops && !(options.fill instanceof fabric.Gradient)) {
@@ -318,7 +385,6 @@
318
385
 
319
386
  /**
320
387
  * @private
321
- * @method _initPattern
322
388
  */
323
389
  _initPattern: function(options) {
324
390
  if (options.fill && options.fill.source && !(options.fill instanceof fabric.Pattern)) {
@@ -331,7 +397,6 @@
331
397
 
332
398
  /**
333
399
  * @private
334
- * @method _initShadow
335
400
  */
336
401
  _initShadow: function(options) {
337
402
  if (options.shadow && !(options.shadow instanceof fabric.Shadow)) {
@@ -339,9 +404,20 @@
339
404
  }
340
405
  },
341
406
 
407
+ /**
408
+ * @private
409
+ */
410
+ _initClipping: function(options) {
411
+ if (!options.clipTo || typeof options.clipTo !== 'string') return;
412
+
413
+ var functionBody = fabric.util.getFunctionBody(options.clipTo);
414
+ if (typeof functionBody !== 'undefined') {
415
+ this.clipTo = new Function('ctx', functionBody);
416
+ }
417
+ },
418
+
342
419
  /**
343
420
  * Sets object's properties from options
344
- * @method setOptions
345
421
  * @param {Object} [options]
346
422
  */
347
423
  setOptions: function(options) {
@@ -351,17 +427,18 @@
351
427
  this._initGradient(options);
352
428
  this._initPattern(options);
353
429
  this._initShadow(options);
430
+ this._initClipping(options);
354
431
  },
355
432
 
356
433
  /**
357
434
  * Transforms context when rendering an object
358
- * @method transform
359
435
  * @param {CanvasRenderingContext2D} ctx Context
436
+ * @param {Boolean} fromLeft When true, context is transformed to object's top/left corner. This is used when rendering text on Node
360
437
  */
361
- transform: function(ctx) {
438
+ transform: function(ctx, fromLeft) {
362
439
  ctx.globalAlpha = this.opacity;
363
440
 
364
- var center = this.getCenterPoint();
441
+ var center = fromLeft ? this._getLeftTopCoords() : this.getCenterPoint();
365
442
  ctx.translate(center.x, center.y);
366
443
  ctx.rotate(degreesToRadians(this.angle));
367
444
  ctx.scale(
@@ -372,9 +449,8 @@
372
449
 
373
450
  /**
374
451
  * Returns an object representation of an instance
375
- * @method toObject
376
- * @param {Array} propertiesToInclude
377
- * @return {Object} object representation of an instance
452
+ * @param {Array} [propertiesToInclude] Any properties that you might want to additionally include in the output
453
+ * @return {Object} Object representation of an instance
378
454
  */
379
455
  toObject: function(propertiesToInclude) {
380
456
 
@@ -391,8 +467,11 @@
391
467
  fill: (this.fill && this.fill.toObject) ? this.fill.toObject() : this.fill,
392
468
  overlayFill: this.overlayFill,
393
469
  stroke: (this.stroke && this.stroke.toObject) ? this.stroke.toObject() : this.stroke,
394
- strokeWidth: this.strokeWidth,
470
+ strokeWidth: toFixed(this.strokeWidth, NUM_FRACTION_DIGITS),
395
471
  strokeDashArray: this.strokeDashArray,
472
+ strokeLineCap: this.strokeLineCap,
473
+ strokeLineJoin: this.strokeLineJoin,
474
+ strokeMiterLimit: toFixed(this.strokeMiterLimit, NUM_FRACTION_DIGITS),
396
475
  scaleX: toFixed(this.scaleX, NUM_FRACTION_DIGITS),
397
476
  scaleY: toFixed(this.scaleY, NUM_FRACTION_DIGITS),
398
477
  angle: toFixed(this.getAngle(), NUM_FRACTION_DIGITS),
@@ -405,7 +484,9 @@
405
484
  hasRotatingPoint: this.hasRotatingPoint,
406
485
  transparentCorners: this.transparentCorners,
407
486
  perPixelTargetFind: this.perPixelTargetFind,
408
- shadow: (this.shadow && this.shadow.toObject) ? this.shadow.toObject() : this.shadow
487
+ shadow: (this.shadow && this.shadow.toObject) ? this.shadow.toObject() : this.shadow,
488
+ visible: this.visible,
489
+ clipTo: this.clipTo && String(this.clipTo)
409
490
  };
410
491
 
411
492
  if (!this.includeDefaultValues) {
@@ -418,33 +499,35 @@
418
499
 
419
500
  /**
420
501
  * Returns (dataless) object representation of an instance
421
- * @method toDatalessObject
422
- * @param {Array} [propertiesToInclude]
423
- * @return {Object} object representation of an instance
502
+ * @param {Array} [propertiesToInclude] Any properties that you might want to additionally include in the output
503
+ * @return {Object} Object representation of an instance
424
504
  */
425
505
  toDatalessObject: function(propertiesToInclude) {
426
506
  // will be overwritten by subclasses
427
507
  return this.toObject(propertiesToInclude);
428
508
  },
429
509
 
510
+ /* _TO_SVG_START_ */
430
511
  /**
431
512
  * Returns styles-string for svg-export
432
- * @method getSvgStyles
433
513
  * @return {String}
434
514
  */
435
515
  getSvgStyles: function() {
436
516
  return [
437
517
  "stroke: ", (this.stroke ? this.stroke : 'none'), "; ",
438
518
  "stroke-width: ", (this.strokeWidth ? this.strokeWidth : '0'), "; ",
439
- "stroke-dasharray: ", (this.strokeDashArray ? this.strokeDashArray.join(' ') : "; "),
440
- "fill: ", (this.fill ? this.fill : 'none'), "; ",
441
- "opacity: ", (this.opacity ? this.opacity : '1'), ";"
519
+ "stroke-dasharray: ", (this.strokeDashArray ? this.strokeDashArray.join(' ') : ''), "; ",
520
+ "stroke-linecap: ", (this.strokeLineCap ? this.strokeLineCap : 'butt'), "; ",
521
+ "stroke-linejoin: ", (this.strokeLineJoin ? this.strokeLineJoin : 'miter'), "; ",
522
+ "stroke-miterlimit: ", (this.strokeMiterLimit ? this.strokeMiterLimit : '4'), "; ",
523
+ "fill: ", (this.fill ? (this.fill && this.fill.toLive ? 'url(#SVGID_' + this.fill.id + ')' : this.fill) : 'none'), "; ",
524
+ "opacity: ", (typeof this.opacity !== 'undefined' ? this.opacity : '1'), ";",
525
+ (this.visible ? '' : " visibility: hidden;")
442
526
  ].join("");
443
527
  },
444
528
 
445
529
  /**
446
530
  * Returns transform-string for svg-export
447
- * @method getSvgTransform
448
531
  * @return {String}
449
532
  */
450
533
  getSvgTransform: function() {
@@ -476,10 +559,11 @@
476
559
 
477
560
  return [ translatePart, anglePart, scalePart, flipXPart, flipYPart ].join('');
478
561
  },
562
+ /* _TO_SVG_END_ */
479
563
 
480
564
  /**
481
565
  * @private
482
- * @method _removeDefaultValues
566
+ * @param {Object} object
483
567
  */
484
568
  _removeDefaultValues: function(object) {
485
569
  var defaultOptions = fabric.Object.prototype.options;
@@ -493,25 +577,6 @@
493
577
  return object;
494
578
  },
495
579
 
496
- /**
497
- * Returns true if an object is in its active state
498
- * @return {Boolean} true if an object is in its active state
499
- */
500
- isActive: function() {
501
- return !!this.active;
502
- },
503
-
504
- /**
505
- * Sets state of an object - `true` makes it active, `false` - inactive
506
- * @param {Boolean} active
507
- * @return {fabric.Object} thisArg
508
- * @chainable
509
- */
510
- setActive: function(active) {
511
- this.active = !!active;
512
- return this;
513
- },
514
-
515
580
  /**
516
581
  * Returns a string representation of an instance
517
582
  * @return {String}
@@ -522,7 +587,6 @@
522
587
 
523
588
  /**
524
589
  * Basic getter
525
- * @method get
526
590
  * @param {String} property
527
591
  * @return {Any} value of a property
528
592
  */
@@ -531,11 +595,10 @@
531
595
  },
532
596
 
533
597
  /**
534
- * Sets property to a given value
535
- * @method set
536
- * @param {String} name
537
- * @param {Object|Function} value
538
- * @return {fabric.Group} thisArg
598
+ * Sets property to a given value. When changing position/dimension -related properties (left, top, scale, angle, etc.) `set` does not update position of object's borders/controls. If you need to update those, call `setCoords()`.
599
+ * @param {String|Object} key (if object, iterate over the object properties)
600
+ * @param {Object|Function} value (if function, the value is passed into it and its return value is used as a new one)
601
+ * @return {fabric.Object} thisArg
539
602
  * @chainable
540
603
  */
541
604
  set: function(key, value) {
@@ -545,7 +608,7 @@
545
608
  }
546
609
  }
547
610
  else {
548
- if (typeof value === 'function') {
611
+ if (typeof value === 'function' && key !== 'clipTo') {
549
612
  this._set(key, value(this.get(key)));
550
613
  }
551
614
  else {
@@ -557,9 +620,9 @@
557
620
 
558
621
  /**
559
622
  * @private
560
- * @method _set
561
- * @param key
562
- * @param value
623
+ * @param {String} key
624
+ * @param {Any} value
625
+ * @return {fabric.Object} thisArg
563
626
  */
564
627
  _set: function(key, value) {
565
628
  var shouldConstrainValue = (key === 'scaleX' || key === 'scaleY');
@@ -586,7 +649,6 @@
586
649
 
587
650
  /**
588
651
  * Toggles specified property from `true` to `false` or from `false` to `true`
589
- * @method toggle
590
652
  * @param {String} property property to toggle
591
653
  * @return {fabric.Object} thisArg
592
654
  * @chainable
@@ -601,7 +663,6 @@
601
663
 
602
664
  /**
603
665
  * Sets sourcePath of an object
604
- * @method setSourcePath
605
666
  * @param {String} value
606
667
  * @return {fabric.Object} thisArg
607
668
  * @chainable
@@ -613,14 +674,12 @@
613
674
 
614
675
  /**
615
676
  * Renders an object on a specified context
616
- * @method render
617
677
  * @param {CanvasRenderingContext2D} ctx context to render on
618
- * @param {Boolean} noTransform
678
+ * @param {Boolean} [noTransform] When true, context is not transformed
619
679
  */
620
680
  render: function(ctx, noTransform) {
621
-
622
- // do not render if width or height are zeros
623
- if (this.width === 0 || this.height === 0) return;
681
+ // do not render if width/height are zeros or object is not visible
682
+ if (this.width === 0 || this.height === 0 || !this.visible) return;
624
683
 
625
684
  ctx.save();
626
685
 
@@ -633,14 +692,14 @@
633
692
  this.transform(ctx);
634
693
  }
635
694
 
636
- if (this.stroke || this.strokeDashArray) {
695
+ if (this.stroke) {
637
696
  ctx.lineWidth = this.strokeWidth;
638
- if (this.stroke && this.stroke.toLive) {
639
- ctx.strokeStyle = this.stroke.toLive(ctx);
640
- }
641
- else {
642
- ctx.strokeStyle = this.stroke;
643
- }
697
+ ctx.lineCap = this.strokeLineCap;
698
+ ctx.lineJoin = this.strokeLineJoin;
699
+ ctx.miterLimit = this.strokeMiterLimit;
700
+ ctx.strokeStyle = this.stroke.toLive
701
+ ? this.stroke.toLive(ctx)
702
+ : this.stroke;
644
703
  }
645
704
 
646
705
  if (this.overlayFill) {
@@ -658,7 +717,9 @@
658
717
  }
659
718
 
660
719
  this._setShadow(ctx);
720
+ this.clipTo && fabric.util.clipContext(this, ctx);
661
721
  this._render(ctx, noTransform);
722
+ this.clipTo && ctx.restore();
662
723
  this._removeShadow(ctx);
663
724
 
664
725
  if (this.active && !noTransform) {
@@ -670,7 +731,7 @@
670
731
 
671
732
  /**
672
733
  * @private
673
- * @method _setShadow
734
+ * @param {CanvasRenderingContext2D} ctx Context to render on
674
735
  */
675
736
  _setShadow: function(ctx) {
676
737
  if (!this.shadow) return;
@@ -683,18 +744,69 @@
683
744
 
684
745
  /**
685
746
  * @private
686
- * @method _removeShadow
747
+ * @param {CanvasRenderingContext2D} ctx Context to render on
687
748
  */
688
749
  _removeShadow: function(ctx) {
689
750
  ctx.shadowColor = '';
690
751
  ctx.shadowBlur = ctx.shadowOffsetX = ctx.shadowOffsetY = 0;
691
752
  },
692
753
 
754
+ /**
755
+ * @private
756
+ * @param {CanvasRenderingContext2D} ctx Context to render on
757
+ */
758
+ _renderFill: function(ctx) {
759
+ if (!this.fill) return;
760
+
761
+ if (this.fill.toLive) {
762
+ ctx.save();
763
+ ctx.translate(
764
+ -this.width / 2 + this.fill.offsetX || 0,
765
+ -this.height / 2 + this.fill.offsetY || 0);
766
+ }
767
+ ctx.fill();
768
+ if (this.fill.toLive) {
769
+ ctx.restore();
770
+ }
771
+ if (this.shadow && !this.shadow.affectStroke) {
772
+ this._removeShadow(ctx);
773
+ }
774
+ },
775
+
776
+ /**
777
+ * @private
778
+ * @param {CanvasRenderingContext2D} ctx Context to render on
779
+ */
780
+ _renderStroke: function(ctx) {
781
+ if (!this.stroke) return;
782
+
783
+ ctx.save();
784
+ if (this.strokeDashArray) {
785
+ // Spec requires the concatenation of two copies the dash list when the number of elements is odd
786
+ if (1 & this.strokeDashArray.length) {
787
+ this.strokeDashArray.push.apply(this.strokeDashArray, this.strokeDashArray);
788
+ }
789
+
790
+ if (supportsLineDash) {
791
+ ctx.setLineDash(this.strokeDashArray);
792
+ this._stroke && this._stroke(ctx);
793
+ }
794
+ else {
795
+ this._renderDashedStroke && this._renderDashedStroke(ctx);
796
+ }
797
+ ctx.stroke();
798
+ }
799
+ else {
800
+ this._stroke ? this._stroke(ctx) : ctx.stroke();
801
+ }
802
+ this._removeShadow(ctx);
803
+ ctx.restore();
804
+ },
805
+
693
806
  /**
694
807
  * Clones an instance
695
- * @method clone
696
808
  * @param {Function} callback Callback is invoked with a clone as a first argument
697
- * @param {Array} propertiesToInclude
809
+ * @param {Array} [propertiesToInclude] Any properties that you might want to additionally include in the outpu
698
810
  * @return {fabric.Object} clone of an instance
699
811
  */
700
812
  clone: function(callback, propertiesToInclude) {
@@ -706,114 +818,68 @@
706
818
 
707
819
  /**
708
820
  * Creates an instance of fabric.Image out of an object
709
- * @method cloneAsImage
710
821
  * @param callback {Function} callback, invoked with an instance as a first argument
711
822
  * @return {fabric.Object} thisArg
712
- * @chainable
713
823
  */
714
824
  cloneAsImage: function(callback) {
715
- if (fabric.Image) {
716
- var i = new Image();
717
-
718
- /** @ignore */
719
- i.onload = function() {
720
- if (callback) {
721
- callback(new fabric.Image(i), orig);
722
- }
723
- i = i.onload = null;
724
- };
725
-
726
- var orig = {
727
- angle: this.get('angle'),
728
- flipX: this.get('flipX'),
729
- flipY: this.get('flipY')
730
- };
731
-
732
- // normalize angle
733
- this.set('angle', 0).set('flipX', false).set('flipY', false);
734
- this.toDataURL(function(dataURL) {
735
- i.src = dataURL;
736
- });
737
- }
825
+ var dataUrl = this.toDataURL();
826
+ fabric.util.loadImage(dataUrl, function(img) {
827
+ if (callback) {
828
+ callback(new fabric.Image(img));
829
+ }
830
+ });
738
831
  return this;
739
832
  },
740
833
 
741
834
  /**
742
835
  * Converts an object into a data-url-like string
743
- * @method toDataURL
744
- * @param callback {Function} callback that recieves resulting data-url string
836
+ * @param {Object} options Options object
837
+ *
838
+ * `format` the format of the output image. Either "jpeg" or "png".
839
+ * `quality` quality level (0..1)
840
+ * `multiplier` multiplier to scale by {Number}
841
+ *
842
+ * @return {String} data url representing an image of this object
745
843
  */
746
- toDataURL: function(callback) {
747
- var el = fabric.util.createCanvasElement();
844
+ toDataURL: function(options) {
845
+ options || (options = { });
748
846
 
847
+ var el = fabric.util.createCanvasElement();
749
848
  el.width = this.getBoundingRectWidth();
750
849
  el.height = this.getBoundingRectHeight();
751
850
 
752
851
  fabric.util.wrapElement(el, 'div');
753
852
 
754
853
  var canvas = new fabric.Canvas(el);
755
- canvas.backgroundColor = 'transparent';
756
- canvas.renderAll();
757
-
758
- if (this.constructor.async) {
759
- this.clone(proceed);
854
+ if (options.format === 'jpeg') {
855
+ canvas.backgroundColor = '#fff';
760
856
  }
761
- else {
762
- proceed(this.clone());
763
- }
764
-
765
- function proceed(clone) {
766
- clone.left = el.width / 2;
767
- clone.top = el.height / 2;
768
857
 
769
- clone.setActive(false);
858
+ var origParams = {
859
+ active: this.get('active'),
860
+ left: this.getLeft(),
861
+ top: this.getTop()
862
+ };
770
863
 
771
- canvas.add(clone);
772
- var data = canvas.toDataURL('png');
864
+ this.set({
865
+ 'active': false,
866
+ left: el.width / 2,
867
+ top: el.height / 2
868
+ });
773
869
 
774
- canvas.dispose();
775
- canvas = clone = null;
870
+ canvas.add(this);
871
+ var data = canvas.toDataURL(options);
776
872
 
777
- callback && callback(data);
778
- }
779
- },
780
-
781
- /**
782
- * Returns true if object state (one of its state properties) was changed
783
- * @method hasStateChanged
784
- * @return {Boolean} true if instance' state has changed
785
- */
786
- hasStateChanged: function() {
787
- return this.stateProperties.some(function(prop) {
788
- return this[prop] !== this.originalState[prop];
789
- }, this);
790
- },
873
+ this.set(origParams).setCoords();
791
874
 
792
- /**
793
- * Saves state of an object
794
- * @method saveState
795
- * @return {fabric.Object} thisArg
796
- * @chainable
797
- */
798
- saveState: function() {
799
- this.stateProperties.forEach(function(prop) {
800
- this.originalState[prop] = this.get(prop);
801
- }, this);
802
- return this;
803
- },
875
+ canvas.dispose();
876
+ canvas = null;
804
877
 
805
- /**
806
- * Setups state of an object
807
- * @method setupState
808
- */
809
- setupState: function() {
810
- this.originalState = { };
811
- this.saveState();
878
+ return data;
812
879
  },
813
880
 
814
881
  /**
815
882
  * Returns true if specified type is identical to the type of an instance
816
- * @method isType
817
883
  * @param type {String} type to check against
818
884
  * @return {Boolean}
819
885
  */
@@ -823,7 +889,6 @@
823
889
 
824
890
  /**
825
891
  * Makes object's color grayscale
826
- * @method toGrayscale
827
892
  * @return {fabric.Object} thisArg
828
893
  */
829
894
  toGrayscale: function() {
@@ -836,8 +901,7 @@
836
901
 
837
902
  /**
838
903
  * Returns complexity of an instance
839
- * @method complexity
840
- * @return {Number} complexity
904
+ * @return {Number} complexity of this instance
841
905
  */
842
906
  complexity: function() {
843
907
  return 0;
@@ -845,9 +909,8 @@
845
909
 
846
910
  /**
847
911
  * Returns a JSON representation of an instance
848
- * @method toJSON
849
- * @param {Array} propertiesToInclude
850
- * @return {String} json
912
+ * @param {Array} [propertiesToInclude] Any properties that you might want to additionally include in the output
913
+ * @return {Object} JSON
851
914
  */
852
915
  toJSON: function(propertiesToInclude) {
853
916
  // delegate, not alias
@@ -855,32 +918,62 @@
855
918
  },
856
919
 
857
920
  /**
858
- * Sets gradient fill of an object
859
- * @method setGradientFill
921
+ * Sets gradient (fill or stroke) of an object
922
+ * @param {String} property Property name 'stroke' or 'fill'
923
+ * @param {Object} [options] Options object
860
924
  */
861
- setGradientFill: function(options) {
862
- this.set('fill', fabric.Gradient.forObject(this, options));
925
+ setGradient: function(property, options) {
926
+ options || (options = { });
927
+
928
+ var gradient = {colorStops: []};
929
+
930
+ gradient.type = options.type || (options.r1 || options.r2 ? 'radial' : 'linear');
931
+ gradient.coords = {
932
+ x1: options.x1,
933
+ y1: options.y1,
934
+ x2: options.x2,
935
+ y2: options.y2
936
+ };
937
+
938
+ if (options.r1 || options.r2) {
939
+ gradient.coords.r1 = options.r1;
940
+ gradient.coords.r2 = options.r2;
941
+ }
942
+
943
+ for (var position in options.colorStops) {
944
+ var color = new fabric.Color(options.colorStops[position]);
945
+ gradient.colorStops.push({offset: position, color: color.toRgb(), opacity: color.getAlpha()});
946
+ }
947
+
948
+ this.set(property, fabric.Gradient.forObject(this, gradient));
863
949
  },
864
950
 
865
951
  /**
866
952
  * Sets pattern fill of an object
867
- * @method setPatternFill
953
+ * @param {Object} [options] Options object
954
+ * @return {fabric.Object} thisArg
955
+ * @chainable
868
956
  */
869
957
  setPatternFill: function(options) {
870
- this.set('fill', new fabric.Pattern(options));
958
+ return this.set('fill', new fabric.Pattern(options));
871
959
  },
872
960
 
873
961
  /**
874
962
  * Sets shadow of an object
875
- * @method setShadow
963
+ * @param {Object} [options] Options object
964
+ * @return {fabric.Object} thisArg
965
+ * @chainable
876
966
  */
877
967
  setShadow: function(options) {
878
- this.set('shadow', new fabric.Shadow(options));
968
+ return this.set('shadow', new fabric.Shadow(options));
879
969
  },
880
970
 
881
971
  /**
882
972
  * Animates object's properties
883
- * @method animate
973
+ * @param {String|Object} property to animate (if string) or properties to animate (if object)
974
+ * @param {Number|Object} value to animate property to (if string was given first) or options object
975
+ * @return {fabric.Object} thisArg
976
+ * @chainable
884
977
  *
885
978
  * As object — multiple properties
886
979
  *
@@ -895,8 +988,14 @@
895
988
  */
896
989
  animate: function() {
897
990
  if (arguments[0] && typeof arguments[0] === 'object') {
898
- for (var prop in arguments[0]) {
899
- this._animate(prop, arguments[0][prop], arguments[1]);
991
+ var propsToAnimate = [ ], prop, skipCallbacks;
992
+ for (prop in arguments[0]) {
993
+ propsToAnimate.push(prop);
994
+ }
995
+ for (var i = 0, len = propsToAnimate.length; i<len; i++) {
996
+ prop = propsToAnimate[i];
997
+ skipCallbacks = i !== len - 1;
998
+ this._animate(prop, arguments[0][prop], arguments[1], skipCallbacks);
900
999
  }
901
1000
  }
902
1001
  else {
@@ -907,9 +1006,12 @@
907
1006
 
908
1007
  /**
909
1008
  * @private
910
- * @method _animate
1009
+ * @param {String} property
1010
+ * @param {String} to
1011
+ * @param {Object} [options]
1012
+ * @param {Boolean} [skipCallbacks]
911
1013
  */
912
- _animate: function(property, to, options) {
1014
+ _animate: function(property, to, options, skipCallbacks) {
913
1015
  var obj = this, propPair;
914
1016
 
915
1017
  to = to.toString();
@@ -953,9 +1055,12 @@
953
1055
  else {
954
1056
  obj.set(property, value);
955
1057
  }
1058
+ if (skipCallbacks) return;
956
1059
  options.onChange && options.onChange();
957
1060
  },
958
1061
  onComplete: function() {
1062
+ if (skipCallbacks) return;
1063
+
959
1064
  obj.setCoords();
960
1065
  options.onComplete && options.onComplete();
961
1066
  }
@@ -964,7 +1069,6 @@
964
1069
 
965
1070
  /**
966
1071
  * Centers object horizontally on canvas to which it was added last
967
- * @method centerH
968
1072
  * @return {fabric.Object} thisArg
969
1073
  */
970
1074
  centerH: function () {
@@ -974,7 +1078,6 @@
974
1078
 
975
1079
  /**
976
1080
  * Centers object vertically on canvas to which it was added last
977
- * @method centerV
978
1081
  * @return {fabric.Object} thisArg
979
1082
  * @chainable
980
1083
  */
@@ -985,7 +1088,6 @@
985
1088
 
986
1089
  /**
987
1090
  * Centers object vertically and horizontally on canvas to which is was added last
988
- * @method center
989
1091
  * @return {fabric.Object} thisArg
990
1092
  * @chainable
991
1093
  */
@@ -995,7 +1097,6 @@
995
1097
 
996
1098
  /**
997
1099
  * Removes object from canvas to which it was added last
998
- * @method remove
999
1100
  * @return {fabric.Object} thisArg
1000
1101
  * @chainable
1001
1102
  */
@@ -1005,45 +1106,79 @@
1005
1106
 
1006
1107
  /**
1007
1108
  * Moves an object to the bottom of the stack of drawn objects
1008
- * @method sendToBack
1009
1109
  * @return {fabric.Object} thisArg
1010
1110
  * @chainable
1011
1111
  */
1012
1112
  sendToBack: function() {
1013
- this.canvas.sendToBack(this);
1113
+ if (this.group) {
1114
+ fabric.StaticCanvas.prototype.sendToBack.call(this.group, this);
1115
+ }
1116
+ else {
1117
+ this.canvas.sendToBack(this);
1118
+ }
1014
1119
  return this;
1015
1120
  },
1016
1121
 
1017
1122
  /**
1018
1123
  * Moves an object to the top of the stack of drawn objects
1019
- * @method bringToFront
1020
1124
  * @return {fabric.Object} thisArg
1021
1125
  * @chainable
1022
1126
  */
1023
1127
  bringToFront: function() {
1024
- this.canvas.bringToFront(this);
1128
+ if (this.group) {
1129
+ fabric.StaticCanvas.prototype.bringToFront.call(this.group, this);
1130
+ }
1131
+ else {
1132
+ this.canvas.bringToFront(this);
1133
+ }
1134
+ return this;
1135
+ },
1136
+
1137
+ /**
1138
+ * Moves an object down in stack of drawn objects
1139
+ * @param intersecting {Boolean} If `true`, send object behind next lower intersecting object
1140
+ * @return {fabric.Object} thisArg
1141
+ * @chainable
1142
+ */
1143
+ sendBackwards: function(intersecting) {
1144
+ if (this.group) {
1145
+ fabric.StaticCanvas.prototype.sendBackwards.call(this.group, this, intersecting);
1146
+ }
1147
+ else {
1148
+ this.canvas.sendBackwards(this, intersecting);
1149
+ }
1025
1150
  return this;
1026
1151
  },
1027
1152
 
1028
1153
  /**
1029
- * Moves an object one level down in stack of drawn objects
1030
- * @method sendBackwards
1154
+ * Moves an object up in stack of drawn objects
1155
+ * @param intersecting {Boolean} If `true`, send object in front of next upper intersecting object
1031
1156
  * @return {fabric.Object} thisArg
1032
1157
  * @chainable
1033
1158
  */
1034
- sendBackwards: function() {
1035
- this.canvas.sendBackwards(this);
1159
+ bringForward: function(intersecting) {
1160
+ if (this.group) {
1161
+ fabric.StaticCanvas.prototype.bringForward.call(this.group, this, intersecting);
1162
+ }
1163
+ else {
1164
+ this.canvas.bringForward(this, intersecting);
1165
+ }
1036
1166
  return this;
1037
1167
  },
1038
1168
 
1039
1169
  /**
1040
- * Moves an object one level up in stack of drawn objects
1041
- * @method bringForward
1170
+ * Moves an object to specified level in stack of drawn objects
1171
+ * @param {Number} index New position of object
1042
1172
  * @return {fabric.Object} thisArg
1043
1173
  * @chainable
1044
1174
  */
1045
- bringForward: function() {
1046
- this.canvas.bringForward(this);
1175
+ moveTo: function(index) {
1176
+ if (this.group) {
1177
+ fabric.StaticCanvas.prototype.moveTo.call(this.group, this, index);
1178
+ }
1179
+ else {
1180
+ this.canvas.moveTo(this, index);
1181
+ }
1047
1182
  return this;
1048
1183
  }
1049
1184
  });
@@ -1059,10 +1194,17 @@
1059
1194
  extend(fabric.Object.prototype, fabric.Observable);
1060
1195
 
1061
1196
  /**
1197
+ * Defines the number of fraction digits when serializing object values. You can use it to increase/decrease precision of such values like left, top, scaleX, scaleY, etc.
1062
1198
  * @static
1063
1199
  * @constant
1064
1200
  * @type Number
1065
1201
  */
1066
1202
  fabric.Object.NUM_FRACTION_DIGITS = 2;
1067
1203
 
1204
+ /**
1205
+ * @static
1206
+ * @type Number
1207
+ */
1208
+ fabric.Object.__uid = 0;
1209
+
1068
1210
  })(typeof exports !== 'undefined' ? exports : this);