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.
Files changed (56) hide show
  1. data/CHANGELOG.md +16 -0
  2. data/README.md +1 -1
  3. data/lib/fabric/rails/version.rb +2 -2
  4. data/vendor/assets/javascripts/event.js +1909 -0
  5. data/vendor/assets/javascripts/fabric.js +64 -16464
  6. data/vendor/assets/javascripts/fabric/HEADER.js +31 -0
  7. data/vendor/assets/javascripts/fabric/canvas.class.js +1007 -0
  8. data/vendor/assets/javascripts/fabric/canvas_animation.mixin.js +113 -0
  9. data/vendor/assets/javascripts/fabric/canvas_events.mixin.js +482 -0
  10. data/vendor/assets/javascripts/fabric/canvas_gestures.mixin.js +79 -0
  11. data/vendor/assets/javascripts/fabric/canvas_serialization.mixin.js +311 -0
  12. data/vendor/assets/javascripts/fabric/circle.class.js +182 -0
  13. data/vendor/assets/javascripts/fabric/color.class.js +284 -0
  14. data/vendor/assets/javascripts/fabric/ellipse.class.js +169 -0
  15. data/vendor/assets/javascripts/fabric/freedrawing.class.js +256 -0
  16. data/vendor/assets/javascripts/fabric/gradient.class.js +211 -0
  17. data/vendor/assets/javascripts/fabric/group.class.js +556 -0
  18. data/vendor/assets/javascripts/fabric/image.class.js +418 -0
  19. data/vendor/assets/javascripts/fabric/image_filters.js +809 -0
  20. data/vendor/assets/javascripts/fabric/intersection.class.js +178 -0
  21. data/vendor/assets/javascripts/fabric/line.class.js +188 -0
  22. data/vendor/assets/javascripts/fabric/log.js +26 -0
  23. data/vendor/assets/javascripts/fabric/node.js +149 -0
  24. data/vendor/assets/javascripts/fabric/object.class.js +1068 -0
  25. data/vendor/assets/javascripts/fabric/object_geometry.mixin.js +308 -0
  26. data/vendor/assets/javascripts/fabric/object_interactivity.mixin.js +496 -0
  27. data/vendor/assets/javascripts/fabric/object_origin.mixin.js +207 -0
  28. data/vendor/assets/javascripts/fabric/object_straightening.mixin.js +94 -0
  29. data/vendor/assets/javascripts/fabric/observable.mixin.js +91 -0
  30. data/vendor/assets/javascripts/fabric/parser.js +750 -0
  31. data/vendor/assets/javascripts/fabric/path.class.js +794 -0
  32. data/vendor/assets/javascripts/fabric/path_group.class.js +240 -0
  33. data/vendor/assets/javascripts/fabric/pattern.class.js +69 -0
  34. data/vendor/assets/javascripts/fabric/point.class.js +327 -0
  35. data/vendor/assets/javascripts/fabric/polygon.class.js +184 -0
  36. data/vendor/assets/javascripts/fabric/polyline.class.js +157 -0
  37. data/vendor/assets/javascripts/fabric/rect.class.js +298 -0
  38. data/vendor/assets/javascripts/fabric/scout.js +45 -0
  39. data/vendor/assets/javascripts/fabric/shadow.class.js +70 -0
  40. data/vendor/assets/javascripts/fabric/stateful.js +88 -0
  41. data/vendor/assets/javascripts/fabric/static_canvas.class.js +1298 -0
  42. data/vendor/assets/javascripts/fabric/text.class.js +934 -0
  43. data/vendor/assets/javascripts/fabric/triangle.class.js +108 -0
  44. data/vendor/assets/javascripts/fabric/util/anim_ease.js +360 -0
  45. data/vendor/assets/javascripts/fabric/util/dom_event.js +237 -0
  46. data/vendor/assets/javascripts/fabric/util/dom_misc.js +245 -0
  47. data/vendor/assets/javascripts/fabric/util/dom_request.js +72 -0
  48. data/vendor/assets/javascripts/fabric/util/dom_style.js +71 -0
  49. data/vendor/assets/javascripts/fabric/util/lang_array.js +250 -0
  50. data/vendor/assets/javascripts/fabric/util/lang_class.js +97 -0
  51. data/vendor/assets/javascripts/fabric/util/lang_function.js +35 -0
  52. data/vendor/assets/javascripts/fabric/util/lang_object.js +34 -0
  53. data/vendor/assets/javascripts/fabric/util/lang_string.js +60 -0
  54. data/vendor/assets/javascripts/fabric/util/misc.js +406 -0
  55. data/vendor/assets/javascripts/json2.js +491 -0
  56. metadata +53 -2
@@ -0,0 +1,1068 @@
1
+ (function(global) {
2
+
3
+ "use strict";
4
+
5
+ var fabric = global.fabric || (global.fabric = { }),
6
+ extend = fabric.util.object.extend,
7
+ toFixed = fabric.util.toFixed,
8
+ capitalize = fabric.util.string.capitalize,
9
+ degreesToRadians = fabric.util.degreesToRadians;
10
+
11
+ if (fabric.Object) {
12
+ return;
13
+ }
14
+
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
+ /**
27
+ * Root object class from which all 2d shape classes inherit from
28
+ * @class Object
29
+ * @memberOf fabric
30
+ */
31
+ fabric.Object = fabric.util.createClass(/** @scope fabric.Object.prototype */ {
32
+
33
+ /**
34
+ * Type of an object (rect, circle, path, etc.)
35
+ * @property
36
+ * @type String
37
+ */
38
+ type: 'object',
39
+
40
+ /**
41
+ * Horizontal origin of transformation of an object (one of "left", "right", "center")
42
+ * @property
43
+ * @type String
44
+ */
45
+ originX: 'center',
46
+
47
+ /**
48
+ * Vertical origin of transformation of an object (one of "top", "bottom", "center")
49
+ * @property
50
+ * @type String
51
+ */
52
+ originY: 'center',
53
+
54
+ /**
55
+ * Top position of an object
56
+ * @property
57
+ * @type Number
58
+ */
59
+ top: 0,
60
+
61
+ /**
62
+ * Left position of an object
63
+ * @property
64
+ * @type Number
65
+ */
66
+ left: 0,
67
+
68
+ /**
69
+ * Object width
70
+ * @property
71
+ * @type Number
72
+ */
73
+ width: 0,
74
+
75
+ /**
76
+ * Object height
77
+ * @property
78
+ * @type Number
79
+ */
80
+ height: 0,
81
+
82
+ /**
83
+ * Object scale factor (horizontal)
84
+ * @property
85
+ * @type Number
86
+ */
87
+ scaleX: 1,
88
+
89
+ /**
90
+ * Object scale factor (vertical)
91
+ * @property
92
+ * @type Number
93
+ */
94
+ scaleY: 1,
95
+
96
+ /**
97
+ * When true, an object is rendered as flipped horizontally
98
+ * @property
99
+ * @type Boolean
100
+ */
101
+ flipX: false,
102
+
103
+ /**
104
+ * When true, an object is rendered as flipped vertically
105
+ * @property
106
+ * @type Boolean
107
+ */
108
+ flipY: false,
109
+
110
+ /**
111
+ * Opacity of an object
112
+ * @property
113
+ * @type Number
114
+ */
115
+ opacity: 1,
116
+
117
+ /**
118
+ * Angle of rotation of an object (in degrees)
119
+ * @property
120
+ * @type Number
121
+ */
122
+ angle: 0,
123
+
124
+ /**
125
+ * Size of object's corners (in pixels)
126
+ * @property
127
+ * @type Number
128
+ */
129
+ cornerSize: 12,
130
+
131
+ /**
132
+ * When true, object's corners are rendered as transparent inside (i.e. stroke instead of fill)
133
+ * @property
134
+ * @type Boolean
135
+ */
136
+ transparentCorners: true,
137
+
138
+ /**
139
+ * Padding between object and its borders (in pixels)
140
+ * @property
141
+ * @type Number
142
+ */
143
+ padding: 0,
144
+
145
+ /**
146
+ * Border color of an object (when it's active)
147
+ * @property
148
+ * @type String
149
+ */
150
+ borderColor: 'rgba(102,153,255,0.75)',
151
+
152
+ /**
153
+ * Corner color of an object (when it's active)
154
+ * @property
155
+ * @type String
156
+ */
157
+ cornerColor: 'rgba(102,153,255,0.5)',
158
+
159
+ /**
160
+ * Color of object's fill
161
+ * @property
162
+ * @type String
163
+ */
164
+ fill: 'rgb(0,0,0)',
165
+
166
+ /**
167
+ * Fill rule used to fill an object
168
+ * @property
169
+ * @type String
170
+ */
171
+ fillRule: 'source-over',
172
+
173
+ /**
174
+ * Overlay fill (takes precedence over fill value)
175
+ * @property
176
+ * @type String
177
+ */
178
+ overlayFill: null,
179
+
180
+ /**
181
+ * When `true`, an object is rendered via stroke and this property specifies its color
182
+ * @property
183
+ * @type String
184
+ */
185
+ stroke: null,
186
+
187
+ /**
188
+ * Width of a stroke used to render this object
189
+ * @property
190
+ * @type Number
191
+ */
192
+ strokeWidth: 1,
193
+
194
+ /**
195
+ * Array specifying dash pattern of an object's stroke
196
+ * @property
197
+ * @type Array
198
+ */
199
+ strokeDashArray: null,
200
+
201
+ /**
202
+ * Shadow object representing shadow of this shape
203
+ * @property
204
+ * @type fabric.Shadow
205
+ */
206
+ shadow: null,
207
+
208
+ /**
209
+ * Border opacity when object is active and moving
210
+ * @property
211
+ * @type Number
212
+ */
213
+ borderOpacityWhenMoving: 0.4,
214
+
215
+ /**
216
+ * Border scale factor
217
+ * @property
218
+ * @type Number
219
+ */
220
+ borderScaleFactor: 1,
221
+
222
+ /**
223
+ * Transform matrix (similar to SVG's transform matrix)
224
+ * @property
225
+ * @type Array
226
+ */
227
+ transformMatrix: null,
228
+
229
+ /**
230
+ * Minimum allowed scale value of an object
231
+ * @property
232
+ * @type Number
233
+ */
234
+ minScaleLimit: 0.01,
235
+
236
+ /**
237
+ * When set to `false`, an object can not be selected for modification (using either point-click-based or group-based selection)
238
+ * @property
239
+ * @type Boolean
240
+ */
241
+ selectable: true,
242
+
243
+ /**
244
+ * When set to `false`, object's controls are not displayed and can not be used to manipulate object
245
+ * @property
246
+ * @type Boolean
247
+ */
248
+ hasControls: true,
249
+
250
+ /**
251
+ * When set to `false`, object's borders are not rendered
252
+ * @property
253
+ * @type Boolean
254
+ */
255
+ hasBorders: true,
256
+
257
+ /**
258
+ * When set to `false`, object's rotating point will not be visible or selectable
259
+ * @property
260
+ * @type Boolean
261
+ */
262
+ hasRotatingPoint: true,
263
+
264
+ /**
265
+ * Offset for object's rotating point (when enabled via `hasRotatingPoint`)
266
+ * @property
267
+ * @type Number
268
+ */
269
+ rotatingPointOffset: 40,
270
+
271
+ /**
272
+ * When set to `true`, objects are "found" on canvas on per-pixel basis rather than according to bounding box
273
+ * @property
274
+ * @type Boolean
275
+ */
276
+ perPixelTargetFind: false,
277
+
278
+ /**
279
+ * When `false`, default object's values are not included in its serialization
280
+ * @property
281
+ * @type Boolean
282
+ */
283
+ includeDefaultValues: true,
284
+
285
+ /**
286
+ * List of properties to consider when checking if state of an object is changed (fabric.Object#hasStateChanged);
287
+ * as well as for history (undo/redo) purposes
288
+ * @property
289
+ * @type Array
290
+ */
291
+ stateProperties: (
292
+ 'top left width height scaleX scaleY flipX flipY ' +
293
+ 'angle opacity cornerSize fill overlayFill originX originY ' +
294
+ 'stroke strokeWidth strokeDashArray fillRule ' +
295
+ 'borderScaleFactor transformMatrix selectable shadow'
296
+ ).split(' '),
297
+
298
+ /**
299
+ * Constructor
300
+ * @method initialize
301
+ * @param {Object} [options] Options object
302
+ */
303
+ initialize: function(options) {
304
+ if (options) {
305
+ this.setOptions(options);
306
+ }
307
+ },
308
+
309
+ /**
310
+ * @private
311
+ * @method _initGradient
312
+ */
313
+ _initGradient: function(options) {
314
+ if (options.fill && options.fill.colorStops && !(options.fill instanceof fabric.Gradient)) {
315
+ this.set('fill', new fabric.Gradient(options.fill));
316
+ }
317
+ },
318
+
319
+ /**
320
+ * @private
321
+ * @method _initPattern
322
+ */
323
+ _initPattern: function(options) {
324
+ if (options.fill && options.fill.source && !(options.fill instanceof fabric.Pattern)) {
325
+ this.set('fill', new fabric.Pattern(options.fill));
326
+ }
327
+ if (options.stroke && options.stroke.source && !(options.stroke instanceof fabric.Pattern)) {
328
+ this.set('stroke', new fabric.Pattern(options.stroke));
329
+ }
330
+ },
331
+
332
+ /**
333
+ * @private
334
+ * @method _initShadow
335
+ */
336
+ _initShadow: function(options) {
337
+ if (options.shadow && !(options.shadow instanceof fabric.Shadow)) {
338
+ this.setShadow(options.shadow);
339
+ }
340
+ },
341
+
342
+ /**
343
+ * Sets object's properties from options
344
+ * @method setOptions
345
+ * @param {Object} [options]
346
+ */
347
+ setOptions: function(options) {
348
+ for (var prop in options) {
349
+ this.set(prop, options[prop]);
350
+ }
351
+ this._initGradient(options);
352
+ this._initPattern(options);
353
+ this._initShadow(options);
354
+ },
355
+
356
+ /**
357
+ * Transforms context when rendering an object
358
+ * @method transform
359
+ * @param {CanvasRenderingContext2D} ctx Context
360
+ */
361
+ transform: function(ctx) {
362
+ ctx.globalAlpha = this.opacity;
363
+
364
+ var center = this.getCenterPoint();
365
+ ctx.translate(center.x, center.y);
366
+ ctx.rotate(degreesToRadians(this.angle));
367
+ ctx.scale(
368
+ this.scaleX * (this.flipX ? -1 : 1),
369
+ this.scaleY * (this.flipY ? -1 : 1)
370
+ );
371
+ },
372
+
373
+ /**
374
+ * Returns an object representation of an instance
375
+ * @method toObject
376
+ * @param {Array} propertiesToInclude
377
+ * @return {Object} object representation of an instance
378
+ */
379
+ toObject: function(propertiesToInclude) {
380
+
381
+ var NUM_FRACTION_DIGITS = fabric.Object.NUM_FRACTION_DIGITS;
382
+
383
+ var object = {
384
+ type: this.type,
385
+ originX: this.originX,
386
+ originY: this.originY,
387
+ left: toFixed(this.left, NUM_FRACTION_DIGITS),
388
+ top: toFixed(this.top, NUM_FRACTION_DIGITS),
389
+ width: toFixed(this.width, NUM_FRACTION_DIGITS),
390
+ height: toFixed(this.height, NUM_FRACTION_DIGITS),
391
+ fill: (this.fill && this.fill.toObject) ? this.fill.toObject() : this.fill,
392
+ overlayFill: this.overlayFill,
393
+ stroke: (this.stroke && this.stroke.toObject) ? this.stroke.toObject() : this.stroke,
394
+ strokeWidth: this.strokeWidth,
395
+ strokeDashArray: this.strokeDashArray,
396
+ scaleX: toFixed(this.scaleX, NUM_FRACTION_DIGITS),
397
+ scaleY: toFixed(this.scaleY, NUM_FRACTION_DIGITS),
398
+ angle: toFixed(this.getAngle(), NUM_FRACTION_DIGITS),
399
+ flipX: this.flipX,
400
+ flipY: this.flipY,
401
+ opacity: toFixed(this.opacity, NUM_FRACTION_DIGITS),
402
+ selectable: this.selectable,
403
+ hasControls: this.hasControls,
404
+ hasBorders: this.hasBorders,
405
+ hasRotatingPoint: this.hasRotatingPoint,
406
+ transparentCorners: this.transparentCorners,
407
+ perPixelTargetFind: this.perPixelTargetFind,
408
+ shadow: (this.shadow && this.shadow.toObject) ? this.shadow.toObject() : this.shadow
409
+ };
410
+
411
+ if (!this.includeDefaultValues) {
412
+ object = this._removeDefaultValues(object);
413
+ }
414
+ fabric.util.populateWithProperties(this, object, propertiesToInclude);
415
+
416
+ return object;
417
+ },
418
+
419
+ /**
420
+ * Returns (dataless) object representation of an instance
421
+ * @method toDatalessObject
422
+ * @param {Array} [propertiesToInclude]
423
+ * @return {Object} object representation of an instance
424
+ */
425
+ toDatalessObject: function(propertiesToInclude) {
426
+ // will be overwritten by subclasses
427
+ return this.toObject(propertiesToInclude);
428
+ },
429
+
430
+ /**
431
+ * Returns styles-string for svg-export
432
+ * @method getSvgStyles
433
+ * @return {String}
434
+ */
435
+ getSvgStyles: function() {
436
+ return [
437
+ "stroke: ", (this.stroke ? this.stroke : 'none'), "; ",
438
+ "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'), ";"
442
+ ].join("");
443
+ },
444
+
445
+ /**
446
+ * Returns transform-string for svg-export
447
+ * @method getSvgTransform
448
+ * @return {String}
449
+ */
450
+ getSvgTransform: function() {
451
+ var angle = this.getAngle();
452
+ var center = this.getCenterPoint();
453
+
454
+ var NUM_FRACTION_DIGITS = fabric.Object.NUM_FRACTION_DIGITS;
455
+
456
+ var translatePart = "translate(" +
457
+ toFixed(center.x, NUM_FRACTION_DIGITS) +
458
+ " " +
459
+ toFixed(center.y, NUM_FRACTION_DIGITS) +
460
+ ")";
461
+
462
+ var anglePart = angle !== 0
463
+ ? (" rotate(" + toFixed(angle, NUM_FRACTION_DIGITS) + ")")
464
+ : '';
465
+
466
+ var scalePart = (this.scaleX === 1 && this.scaleY === 1)
467
+ ? '' :
468
+ (" scale(" +
469
+ toFixed(this.scaleX, NUM_FRACTION_DIGITS) +
470
+ " " +
471
+ toFixed(this.scaleY, NUM_FRACTION_DIGITS) +
472
+ ")");
473
+
474
+ var flipXPart = this.flipX ? "matrix(-1 0 0 1 0 0) " : "";
475
+ var flipYPart = this.flipY ? "matrix(1 0 0 -1 0 0)" : "";
476
+
477
+ return [ translatePart, anglePart, scalePart, flipXPart, flipYPart ].join('');
478
+ },
479
+
480
+ /**
481
+ * @private
482
+ * @method _removeDefaultValues
483
+ */
484
+ _removeDefaultValues: function(object) {
485
+ var defaultOptions = fabric.Object.prototype.options;
486
+ if (defaultOptions) {
487
+ this.stateProperties.forEach(function(prop) {
488
+ if (object[prop] === defaultOptions[prop]) {
489
+ delete object[prop];
490
+ }
491
+ });
492
+ }
493
+ return object;
494
+ },
495
+
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
+ /**
516
+ * Returns a string representation of an instance
517
+ * @return {String}
518
+ */
519
+ toString: function() {
520
+ return "#<fabric." + capitalize(this.type) + ">";
521
+ },
522
+
523
+ /**
524
+ * Basic getter
525
+ * @method get
526
+ * @param {String} property
527
+ * @return {Any} value of a property
528
+ */
529
+ get: function(property) {
530
+ return this[property];
531
+ },
532
+
533
+ /**
534
+ * Sets property to a given value
535
+ * @method set
536
+ * @param {String} name
537
+ * @param {Object|Function} value
538
+ * @return {fabric.Group} thisArg
539
+ * @chainable
540
+ */
541
+ set: function(key, value) {
542
+ if (typeof key === 'object') {
543
+ for (var prop in key) {
544
+ this._set(prop, key[prop]);
545
+ }
546
+ }
547
+ else {
548
+ if (typeof value === 'function') {
549
+ this._set(key, value(this.get(key)));
550
+ }
551
+ else {
552
+ this._set(key, value);
553
+ }
554
+ }
555
+ return this;
556
+ },
557
+
558
+ /**
559
+ * @private
560
+ * @method _set
561
+ * @param key
562
+ * @param value
563
+ */
564
+ _set: function(key, value) {
565
+ var shouldConstrainValue = (key === 'scaleX' || key === 'scaleY');
566
+
567
+ if (shouldConstrainValue) {
568
+ value = this._constrainScale(value);
569
+ }
570
+ if (key === 'scaleX' && value < 0) {
571
+ this.flipX = !this.flipX;
572
+ value *= -1;
573
+ }
574
+ else if (key === 'scaleY' && value < 0) {
575
+ this.flipY = !this.flipY;
576
+ value *= -1;
577
+ }
578
+ else if (key === 'width' || key === 'height') {
579
+ this.minScaleLimit = toFixed(Math.min(0.1, 1/Math.max(this.width, this.height)), 2);
580
+ }
581
+
582
+ this[key] = value;
583
+
584
+ return this;
585
+ },
586
+
587
+ /**
588
+ * Toggles specified property from `true` to `false` or from `false` to `true`
589
+ * @method toggle
590
+ * @param {String} property property to toggle
591
+ * @return {fabric.Object} thisArg
592
+ * @chainable
593
+ */
594
+ toggle: function(property) {
595
+ var value = this.get(property);
596
+ if (typeof value === 'boolean') {
597
+ this.set(property, !value);
598
+ }
599
+ return this;
600
+ },
601
+
602
+ /**
603
+ * Sets sourcePath of an object
604
+ * @method setSourcePath
605
+ * @param {String} value
606
+ * @return {fabric.Object} thisArg
607
+ * @chainable
608
+ */
609
+ setSourcePath: function(value) {
610
+ this.sourcePath = value;
611
+ return this;
612
+ },
613
+
614
+ /**
615
+ * Renders an object on a specified context
616
+ * @method render
617
+ * @param {CanvasRenderingContext2D} ctx context to render on
618
+ * @param {Boolean} noTransform
619
+ */
620
+ render: function(ctx, noTransform) {
621
+
622
+ // do not render if width or height are zeros
623
+ if (this.width === 0 || this.height === 0) return;
624
+
625
+ ctx.save();
626
+
627
+ var m = this.transformMatrix;
628
+ if (m && !this.group) {
629
+ ctx.setTransform(m[0], m[1], m[2], m[3], m[4], m[5]);
630
+ }
631
+
632
+ if (!noTransform) {
633
+ this.transform(ctx);
634
+ }
635
+
636
+ if (this.stroke || this.strokeDashArray) {
637
+ 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
+ }
644
+ }
645
+
646
+ if (this.overlayFill) {
647
+ ctx.fillStyle = this.overlayFill;
648
+ }
649
+ else if (this.fill) {
650
+ ctx.fillStyle = this.fill.toLive
651
+ ? this.fill.toLive(ctx)
652
+ : this.fill;
653
+ }
654
+
655
+ if (m && this.group) {
656
+ ctx.translate(-this.group.width/2, -this.group.height/2);
657
+ ctx.transform(m[0], m[1], m[2], m[3], m[4], m[5]);
658
+ }
659
+
660
+ this._setShadow(ctx);
661
+ this._render(ctx, noTransform);
662
+ this._removeShadow(ctx);
663
+
664
+ if (this.active && !noTransform) {
665
+ this.drawBorders(ctx);
666
+ this.drawControls(ctx);
667
+ }
668
+ ctx.restore();
669
+ },
670
+
671
+ /**
672
+ * @private
673
+ * @method _setShadow
674
+ */
675
+ _setShadow: function(ctx) {
676
+ if (!this.shadow) return;
677
+
678
+ ctx.shadowColor = this.shadow.color;
679
+ ctx.shadowBlur = this.shadow.blur;
680
+ ctx.shadowOffsetX = this.shadow.offsetX;
681
+ ctx.shadowOffsetY = this.shadow.offsetY;
682
+ },
683
+
684
+ /**
685
+ * @private
686
+ * @method _removeShadow
687
+ */
688
+ _removeShadow: function(ctx) {
689
+ ctx.shadowColor = '';
690
+ ctx.shadowBlur = ctx.shadowOffsetX = ctx.shadowOffsetY = 0;
691
+ },
692
+
693
+ /**
694
+ * Clones an instance
695
+ * @method clone
696
+ * @param {Function} callback Callback is invoked with a clone as a first argument
697
+ * @param {Array} propertiesToInclude
698
+ * @return {fabric.Object} clone of an instance
699
+ */
700
+ clone: function(callback, propertiesToInclude) {
701
+ if (this.constructor.fromObject) {
702
+ return this.constructor.fromObject(this.toObject(propertiesToInclude), callback);
703
+ }
704
+ return new fabric.Object(this.toObject(propertiesToInclude));
705
+ },
706
+
707
+ /**
708
+ * Creates an instance of fabric.Image out of an object
709
+ * @method cloneAsImage
710
+ * @param callback {Function} callback, invoked with an instance as a first argument
711
+ * @return {fabric.Object} thisArg
712
+ * @chainable
713
+ */
714
+ 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
+ }
738
+ return this;
739
+ },
740
+
741
+ /**
742
+ * Converts an object into a data-url-like string
743
+ * @method toDataURL
744
+ * @param callback {Function} callback that recieves resulting data-url string
745
+ */
746
+ toDataURL: function(callback) {
747
+ var el = fabric.util.createCanvasElement();
748
+
749
+ el.width = this.getBoundingRectWidth();
750
+ el.height = this.getBoundingRectHeight();
751
+
752
+ fabric.util.wrapElement(el, 'div');
753
+
754
+ var canvas = new fabric.Canvas(el);
755
+ canvas.backgroundColor = 'transparent';
756
+ canvas.renderAll();
757
+
758
+ if (this.constructor.async) {
759
+ this.clone(proceed);
760
+ }
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
+
769
+ clone.setActive(false);
770
+
771
+ canvas.add(clone);
772
+ var data = canvas.toDataURL('png');
773
+
774
+ canvas.dispose();
775
+ canvas = clone = null;
776
+
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
+ },
791
+
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
+ },
804
+
805
+ /**
806
+ * Setups state of an object
807
+ * @method setupState
808
+ */
809
+ setupState: function() {
810
+ this.originalState = { };
811
+ this.saveState();
812
+ },
813
+
814
+ /**
815
+ * Returns true if specified type is identical to the type of an instance
816
+ * @method isType
817
+ * @param type {String} type to check against
818
+ * @return {Boolean}
819
+ */
820
+ isType: function(type) {
821
+ return this.type === type;
822
+ },
823
+
824
+ /**
825
+ * Makes object's color grayscale
826
+ * @method toGrayscale
827
+ * @return {fabric.Object} thisArg
828
+ */
829
+ toGrayscale: function() {
830
+ var fillValue = this.get('fill');
831
+ if (fillValue) {
832
+ this.set('overlayFill', new fabric.Color(fillValue).toGrayscale().toRgb());
833
+ }
834
+ return this;
835
+ },
836
+
837
+ /**
838
+ * Returns complexity of an instance
839
+ * @method complexity
840
+ * @return {Number} complexity
841
+ */
842
+ complexity: function() {
843
+ return 0;
844
+ },
845
+
846
+ /**
847
+ * Returns a JSON representation of an instance
848
+ * @method toJSON
849
+ * @param {Array} propertiesToInclude
850
+ * @return {String} json
851
+ */
852
+ toJSON: function(propertiesToInclude) {
853
+ // delegate, not alias
854
+ return this.toObject(propertiesToInclude);
855
+ },
856
+
857
+ /**
858
+ * Sets gradient fill of an object
859
+ * @method setGradientFill
860
+ */
861
+ setGradientFill: function(options) {
862
+ this.set('fill', fabric.Gradient.forObject(this, options));
863
+ },
864
+
865
+ /**
866
+ * Sets pattern fill of an object
867
+ * @method setPatternFill
868
+ */
869
+ setPatternFill: function(options) {
870
+ this.set('fill', new fabric.Pattern(options));
871
+ },
872
+
873
+ /**
874
+ * Sets shadow of an object
875
+ * @method setShadow
876
+ */
877
+ setShadow: function(options) {
878
+ this.set('shadow', new fabric.Shadow(options));
879
+ },
880
+
881
+ /**
882
+ * Animates object's properties
883
+ * @method animate
884
+ *
885
+ * As object — multiple properties
886
+ *
887
+ * object.animate({ left: ..., top: ... });
888
+ * object.animate({ left: ..., top: ... }, { duration: ... });
889
+ *
890
+ * As string — one property
891
+ *
892
+ * object.animate('left', ...);
893
+ * object.animate('left', { duration: ... });
894
+ *
895
+ */
896
+ animate: function() {
897
+ if (arguments[0] && typeof arguments[0] === 'object') {
898
+ for (var prop in arguments[0]) {
899
+ this._animate(prop, arguments[0][prop], arguments[1]);
900
+ }
901
+ }
902
+ else {
903
+ this._animate.apply(this, arguments);
904
+ }
905
+ return this;
906
+ },
907
+
908
+ /**
909
+ * @private
910
+ * @method _animate
911
+ */
912
+ _animate: function(property, to, options) {
913
+ var obj = this, propPair;
914
+
915
+ to = to.toString();
916
+
917
+ if (!options) {
918
+ options = { };
919
+ }
920
+ else {
921
+ options = fabric.util.object.clone(options);
922
+ }
923
+
924
+ if (~property.indexOf('.')) {
925
+ propPair = property.split('.');
926
+ }
927
+
928
+ var currentValue = propPair
929
+ ? this.get(propPair[0])[propPair[1]]
930
+ : this.get(property);
931
+
932
+ if (!('from' in options)) {
933
+ options.from = currentValue;
934
+ }
935
+
936
+ if (~to.indexOf('=')) {
937
+ to = currentValue + parseFloat(to.replace('=', ''));
938
+ }
939
+ else {
940
+ to = parseFloat(to);
941
+ }
942
+
943
+ fabric.util.animate({
944
+ startValue: options.from,
945
+ endValue: to,
946
+ byValue: options.by,
947
+ easing: options.easing,
948
+ duration: options.duration,
949
+ onChange: function(value) {
950
+ if (propPair) {
951
+ obj[propPair[0]][propPair[1]] = value;
952
+ }
953
+ else {
954
+ obj.set(property, value);
955
+ }
956
+ options.onChange && options.onChange();
957
+ },
958
+ onComplete: function() {
959
+ obj.setCoords();
960
+ options.onComplete && options.onComplete();
961
+ }
962
+ });
963
+ },
964
+
965
+ /**
966
+ * Centers object horizontally on canvas to which it was added last
967
+ * @method centerH
968
+ * @return {fabric.Object} thisArg
969
+ */
970
+ centerH: function () {
971
+ this.canvas.centerObjectH(this);
972
+ return this;
973
+ },
974
+
975
+ /**
976
+ * Centers object vertically on canvas to which it was added last
977
+ * @method centerV
978
+ * @return {fabric.Object} thisArg
979
+ * @chainable
980
+ */
981
+ centerV: function () {
982
+ this.canvas.centerObjectV(this);
983
+ return this;
984
+ },
985
+
986
+ /**
987
+ * Centers object vertically and horizontally on canvas to which is was added last
988
+ * @method center
989
+ * @return {fabric.Object} thisArg
990
+ * @chainable
991
+ */
992
+ center: function () {
993
+ return this.centerH().centerV();
994
+ },
995
+
996
+ /**
997
+ * Removes object from canvas to which it was added last
998
+ * @method remove
999
+ * @return {fabric.Object} thisArg
1000
+ * @chainable
1001
+ */
1002
+ remove: function() {
1003
+ return this.canvas.remove(this);
1004
+ },
1005
+
1006
+ /**
1007
+ * Moves an object to the bottom of the stack of drawn objects
1008
+ * @method sendToBack
1009
+ * @return {fabric.Object} thisArg
1010
+ * @chainable
1011
+ */
1012
+ sendToBack: function() {
1013
+ this.canvas.sendToBack(this);
1014
+ return this;
1015
+ },
1016
+
1017
+ /**
1018
+ * Moves an object to the top of the stack of drawn objects
1019
+ * @method bringToFront
1020
+ * @return {fabric.Object} thisArg
1021
+ * @chainable
1022
+ */
1023
+ bringToFront: function() {
1024
+ this.canvas.bringToFront(this);
1025
+ return this;
1026
+ },
1027
+
1028
+ /**
1029
+ * Moves an object one level down in stack of drawn objects
1030
+ * @method sendBackwards
1031
+ * @return {fabric.Object} thisArg
1032
+ * @chainable
1033
+ */
1034
+ sendBackwards: function() {
1035
+ this.canvas.sendBackwards(this);
1036
+ return this;
1037
+ },
1038
+
1039
+ /**
1040
+ * Moves an object one level up in stack of drawn objects
1041
+ * @method bringForward
1042
+ * @return {fabric.Object} thisArg
1043
+ * @chainable
1044
+ */
1045
+ bringForward: function() {
1046
+ this.canvas.bringForward(this);
1047
+ return this;
1048
+ }
1049
+ });
1050
+
1051
+ fabric.util.createAccessors(fabric.Object);
1052
+
1053
+ /**
1054
+ * Alias for {@link fabric.Object.prototype.setAngle}
1055
+ * @alias rotate -> setAngle
1056
+ */
1057
+ fabric.Object.prototype.rotate = fabric.Object.prototype.setAngle;
1058
+
1059
+ extend(fabric.Object.prototype, fabric.Observable);
1060
+
1061
+ /**
1062
+ * @static
1063
+ * @constant
1064
+ * @type Number
1065
+ */
1066
+ fabric.Object.NUM_FRACTION_DIGITS = 2;
1067
+
1068
+ })(typeof exports !== 'undefined' ? exports : this);