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
@@ -12,35 +12,41 @@
12
12
 
13
13
  /**
14
14
  * Rectangle class
15
- * @class Rect
15
+ * @class fabric.Rect
16
16
  * @extends fabric.Object
17
+ * @return {fabric.Rect} thisArg
17
18
  */
18
- fabric.Rect = fabric.util.createClass(fabric.Object, /** @scope fabric.Rect.prototype */ {
19
+ fabric.Rect = fabric.util.createClass(fabric.Object, /** @lends fabric.Rect.prototype */ {
19
20
 
20
21
  /**
21
22
  * Type of an object
22
- * @property
23
23
  * @type String
24
+ * @default
24
25
  */
25
26
  type: 'rect',
26
27
 
27
28
  /**
28
29
  * Horizontal border radius
29
- * @property
30
30
  * @type Number
31
+ * @default
31
32
  */
32
- rx: 0,
33
+ rx: 0,
33
34
 
34
35
  /**
35
36
  * Vertical border radius
36
- * @property
37
37
  * @type Number
38
+ * @default
38
39
  */
39
- ry: 0,
40
+ ry: 0,
41
+
42
+ /**
43
+ * Used to specify dash pattern for stroke on this object
44
+ * @type Array
45
+ */
46
+ strokeDashArray: null,
40
47
 
41
48
  /**
42
49
  * Constructor
43
- * @method initialize
44
50
  * @param {Object} [options] Options object
45
51
  * @return {Object} thisArg
46
52
  */
@@ -51,15 +57,14 @@
51
57
  this.callSuper('initialize', options);
52
58
  this._initRxRy();
53
59
 
54
- this.x = 0;
55
- this.y = 0;
60
+ this.x = options.x || 0;
61
+ this.y = options.y || 0;
56
62
  },
57
63
 
58
64
  /**
59
65
  * Creates `stateProperties` list on an instance, and adds `fabric.Rect` -specific ones to it
60
66
  * (such as "rx", "ry", etc.)
61
67
  * @private
62
- * @method _initStateProperties
63
68
  */
64
69
  _initStateProperties: function() {
65
70
  this.stateProperties = this.stateProperties.concat(['rx', 'ry']);
@@ -68,7 +73,6 @@
68
73
  /**
69
74
  * Initializes rx/ry attributes
70
75
  * @private
71
- * @method _initRxRy
72
76
  */
73
77
  _initRxRy: function() {
74
78
  if (this.rx && !this.ry) {
@@ -81,7 +85,6 @@
81
85
 
82
86
  /**
83
87
  * @private
84
- * @method _render
85
88
  * @param ctx {CanvasRenderingContext2D} context to render on
86
89
  */
87
90
  _render: function(ctx) {
@@ -90,168 +93,132 @@
90
93
  x = -this.width / 2,
91
94
  y = -this.height / 2,
92
95
  w = this.width,
93
- h = this.height;
96
+ h = this.height,
97
+ isInPathGroup = this.group && this.group.type !== 'group';
94
98
 
95
99
  ctx.beginPath();
96
- ctx.globalAlpha = this.group ? (ctx.globalAlpha * this.opacity) : this.opacity;
100
+ ctx.globalAlpha = isInPathGroup ? (ctx.globalAlpha * this.opacity) : this.opacity;
97
101
 
98
- if (this.transformMatrix && this.group) {
102
+ if (this.transformMatrix && isInPathGroup) {
99
103
  ctx.translate(
100
104
  this.width / 2 + this.x,
101
105
  this.height / 2 + this.y);
102
106
  }
103
- if (!this.transformMatrix && this.group) {
107
+ if (!this.transformMatrix && isInPathGroup) {
104
108
  ctx.translate(
105
109
  -this.group.width / 2 + this.width / 2 + this.x,
106
110
  -this.group.height / 2 + this.height / 2 + this.y);
107
111
  }
108
112
 
113
+ var isRounded = rx !== 0 || ry !== 0;
114
+
109
115
  ctx.moveTo(x+rx, y);
110
116
  ctx.lineTo(x+w-rx, y);
111
- ctx.quadraticCurveTo(x+w, y, x+w, y+ry, x+w, y+ry);
117
+ isRounded && ctx.quadraticCurveTo(x+w, y, x+w, y+ry, x+w, y+ry);
112
118
  ctx.lineTo(x+w, y+h-ry);
113
- ctx.quadraticCurveTo(x+w,y+h,x+w-rx,y+h,x+w-rx,y+h);
119
+ isRounded && ctx.quadraticCurveTo(x+w,y+h,x+w-rx,y+h,x+w-rx,y+h);
114
120
  ctx.lineTo(x+rx,y+h);
115
- ctx.quadraticCurveTo(x,y+h,x,y+h-ry,x,y+h-ry);
121
+ isRounded && ctx.quadraticCurveTo(x,y+h,x,y+h-ry,x,y+h-ry);
116
122
  ctx.lineTo(x,y+ry);
117
- ctx.quadraticCurveTo(x,y,x+rx,y,x+rx,y);
123
+ isRounded && ctx.quadraticCurveTo(x,y,x+rx,y,x+rx,y);
118
124
  ctx.closePath();
119
125
 
120
- if (this.fill) {
121
- ctx.fill();
122
- }
123
-
124
- this._removeShadow(ctx);
125
-
126
- if (this.strokeDashArray) {
127
- this._renderDashedStroke(ctx);
128
- }
129
- else if (this.stroke) {
130
- ctx.stroke();
131
- }
126
+ this._renderFill(ctx);
127
+ this._renderStroke(ctx);
132
128
  },
133
129
 
134
130
  /**
135
131
  * @private
136
- * @method _renderDashedStroke
132
+ * @param ctx {CanvasRenderingContext2D} context to render on
137
133
  */
138
134
  _renderDashedStroke: function(ctx) {
135
+ var x = -this.width/2,
136
+ y = -this.height/2,
137
+ w = this.width,
138
+ h = this.height;
139
139
 
140
- if (1 & this.strokeDashArray.length /* if odd number of items */) {
141
- /* duplicate items */
142
- this.strokeDashArray.push.apply(this.strokeDashArray, this.strokeDashArray);
143
- }
144
-
145
- var i = 0,
146
- x = -this.width/2, y = -this.height/2,
147
- _this = this,
148
- padding = this.padding,
149
- dashedArrayLength = this.strokeDashArray.length;
150
-
151
- ctx.save();
152
140
  ctx.beginPath();
153
-
154
- /** @ignore */
155
- function renderSide(xMultiplier, yMultiplier) {
156
-
157
- var lineLength = 0,
158
- lengthDiff = 0,
159
- sideLength = (yMultiplier ? _this.height : _this.width) + padding * 2;
160
-
161
- while (lineLength < sideLength) {
162
-
163
- var lengthOfSubPath = _this.strokeDashArray[i++];
164
- lineLength += lengthOfSubPath;
165
-
166
- if (lineLength > sideLength) {
167
- lengthDiff = lineLength - sideLength;
168
- }
169
-
170
- // track coords
171
- if (xMultiplier) {
172
- x += (lengthOfSubPath * xMultiplier) - (lengthDiff * xMultiplier || 0);
173
- }
174
- else {
175
- y += (lengthOfSubPath * yMultiplier) - (lengthDiff * yMultiplier || 0);
176
- }
177
-
178
- ctx[1 & i /* odd */ ? 'moveTo' : 'lineTo'](x, y);
179
- if (i >= dashedArrayLength) {
180
- i = 0;
181
- }
182
- }
183
- }
184
-
185
- renderSide(1, 0);
186
- renderSide(0, 1);
187
- renderSide(-1, 0);
188
- renderSide(0, -1);
189
-
190
- ctx.stroke();
141
+ fabric.util.drawDashedLine(ctx, x, y, x+w, y, this.strokeDashArray);
142
+ fabric.util.drawDashedLine(ctx, x+w, y, x+w, y+h, this.strokeDashArray);
143
+ fabric.util.drawDashedLine(ctx, x+w, y+h, x, y+h, this.strokeDashArray);
144
+ fabric.util.drawDashedLine(ctx, x, y+h, x, y, this.strokeDashArray);
191
145
  ctx.closePath();
192
- ctx.restore();
193
146
  },
194
147
 
195
148
  /**
196
- * @method _normalizeLeftTopProperties
197
- * @private
198
149
  * Since coordinate system differs from that of SVG
150
+ * @private
199
151
  */
200
152
  _normalizeLeftTopProperties: function(parsedAttributes) {
201
- if (parsedAttributes.left) {
153
+ if ('left' in parsedAttributes) {
202
154
  this.set('left', parsedAttributes.left + this.getWidth() / 2);
203
155
  }
204
156
  this.set('x', parsedAttributes.left || 0);
205
- if (parsedAttributes.top) {
157
+ if ('top' in parsedAttributes) {
206
158
  this.set('top', parsedAttributes.top + this.getHeight() / 2);
207
159
  }
208
160
  this.set('y', parsedAttributes.top || 0);
209
161
  return this;
210
162
  },
211
163
 
212
- /**
213
- * Returns complexity of an instance
214
- * @method complexity
215
- * @return {Number} complexity
216
- */
217
- complexity: function() {
218
- return 1;
219
- },
220
-
221
164
  /**
222
165
  * Returns object representation of an instance
223
- * @method toObject
224
166
  * @param {Array} propertiesToInclude
225
167
  * @return {Object} object representation of an instance
226
168
  */
227
169
  toObject: function(propertiesToInclude) {
228
170
  return extend(this.callSuper('toObject', propertiesToInclude), {
229
171
  rx: this.get('rx') || 0,
230
- ry: this.get('ry') || 0
172
+ ry: this.get('ry') || 0,
173
+ x: this.get('x'),
174
+ y: this.get('y')
231
175
  });
232
176
  },
233
177
 
178
+ /* _TO_SVG_START_ */
234
179
  /**
235
180
  * Returns svg representation of an instance
236
- * @method toSVG
237
181
  * @return {String} svg representation of an instance
238
182
  */
239
183
  toSVG: function() {
240
- return '<rect ' +
241
- 'x="' + (-1 * this.width / 2) + '" y="' + (-1 * this.height / 2) + '" ' +
242
- 'rx="' + this.get('rx') + '" ry="' + this.get('ry') + '" ' +
243
- 'width="' + this.width + '" height="' + this.height + '" ' +
244
- 'style="' + this.getSvgStyles() + '" ' +
245
- 'transform="' + this.getSvgTransform() + '" ' +
246
- '/>';
184
+ var markup = [];
185
+
186
+ if (this.fill && this.fill.toLive) {
187
+ markup.push(this.fill.toSVG(this, false));
188
+ }
189
+ if (this.stroke && this.stroke.toLive) {
190
+ markup.push(this.stroke.toSVG(this, false));
191
+ }
192
+
193
+ markup.push(
194
+ '<rect ',
195
+ 'x="', (-1 * this.width / 2), '" y="', (-1 * this.height / 2),
196
+ '" rx="', this.get('rx'), '" ry="', this.get('ry'),
197
+ '" width="', this.width, '" height="', this.height,
198
+ '" style="', this.getSvgStyles(),
199
+ '" transform="', this.getSvgTransform(),
200
+ '"/>'
201
+ );
202
+
203
+ return markup.join('');
204
+ },
205
+ /* _TO_SVG_END_ */
206
+
207
+ /**
208
+ * Returns complexity of an instance
209
+ * @return {Number} complexity
210
+ */
211
+ complexity: function() {
212
+ return 1;
247
213
  }
248
214
  });
249
215
 
216
+ /* _FROM_SVG_START_ */
250
217
  /**
251
218
  * List of attribute names to account for when parsing SVG element (used by `fabric.Rect.fromElement`)
252
219
  * @static
253
220
  */
254
- fabric.Rect.ATTRIBUTE_NAMES = 'x y width height rx ry fill fill-opacity opacity stroke stroke-width transform'.split(' ');
221
+ fabric.Rect.ATTRIBUTE_NAMES = fabric.SHARED_ATTRIBUTES.concat('x y rx ry width height'.split(' '));
255
222
 
256
223
  /**
257
224
  * @private
@@ -265,7 +232,6 @@
265
232
  /**
266
233
  * Returns {@link fabric.Rect} instance from an SVG element
267
234
  * @static
268
- * @method fabric.Rect.fromElement
269
235
  * @param {SVGElement} element Element to parse
270
236
  * @param {Object} [options] Options object
271
237
  * @return {fabric.Rect} Instance of fabric.Rect
@@ -283,11 +249,11 @@
283
249
 
284
250
  return rect;
285
251
  };
252
+ /* _FROM_SVG_END_ */
286
253
 
287
254
  /**
288
255
  * Returns {@link fabric.Rect} instance from an object representation
289
256
  * @static
290
- * @method fabric.Rect.fromObject
291
257
  * @param object {Object} object to create an instance from
292
258
  * @return {Object} instance of fabric.Rect
293
259
  */
@@ -295,4 +261,4 @@
295
261
  return new fabric.Rect(object);
296
262
  };
297
263
 
298
- })(typeof exports !== 'undefined' ? exports : this);
264
+ })(typeof exports !== 'undefined' ? exports : this);
@@ -5,25 +5,14 @@
5
5
  var fabric = global.fabric || (global.fabric = { }),
6
6
  extend = fabric.util.object.extend,
7
7
  clone = fabric.util.object.clone,
8
- toFixed = fabric.util.toFixed;
8
+ toFixed = fabric.util.toFixed,
9
+ supportsLineDash = fabric.StaticCanvas.supports('setLineDash');
9
10
 
10
11
  if (fabric.Text) {
11
12
  fabric.warn('fabric.Text is already defined');
12
13
  return;
13
14
  }
14
15
 
15
- var dimensionAffectingProps = {
16
- fontSize: true,
17
- fontWeight: true,
18
- fontFamily: true,
19
- textDecoration: true,
20
- fontStyle: true,
21
- lineHeight: true,
22
- strokeStyle: true,
23
- strokeWidth: true,
24
- text: true
25
- };
26
-
27
16
  var stateProperties = fabric.Object.prototype.stateProperties.concat();
28
17
  stateProperties.push(
29
18
  'fontFamily',
@@ -36,8 +25,6 @@
36
25
  'textAlign',
37
26
  'fontStyle',
38
27
  'lineHeight',
39
- 'strokeStyle',
40
- 'strokeWidth',
41
28
  'backgroundColor',
42
29
  'textBackgroundColor',
43
30
  'useNative'
@@ -45,136 +32,140 @@
45
32
 
46
33
  /**
47
34
  * Text class
48
- * @class Text
35
+ * @class fabric.Text
49
36
  * @extends fabric.Object
37
+ * @return {fabric.Text} thisArg
50
38
  */
51
- fabric.Text = fabric.util.createClass(fabric.Object, /** @scope fabric.Text.prototype */ {
39
+ fabric.Text = fabric.util.createClass(fabric.Object, /** @lends fabric.Text.prototype */ {
40
+
41
+ /**
42
+ * Properties which when set cause object to change dimensions
43
+ * @type Object
44
+ * @private
45
+ */
46
+ _dimensionAffectingProps: {
47
+ fontSize: true,
48
+ fontWeight: true,
49
+ fontFamily: true,
50
+ textDecoration: true,
51
+ fontStyle: true,
52
+ lineHeight: true,
53
+ stroke: true,
54
+ strokeWidth: true,
55
+ text: true
56
+ },
57
+
58
+ /**
59
+ * Type of an object
60
+ * @type String
61
+ * @default
62
+ */
63
+ type: 'text',
52
64
 
53
65
  /**
54
66
  * Font size (in pixels)
55
- * @property
56
67
  * @type Number
68
+ * @default
57
69
  */
58
70
  fontSize: 40,
59
71
 
60
72
  /**
61
73
  * Font weight (e.g. bold, normal, 400, 600, 800)
62
- * @property
63
74
  * @type Number
75
+ * @default
64
76
  */
65
77
  fontWeight: 'normal',
66
78
 
67
79
  /**
68
80
  * Font family
69
- * @property
70
81
  * @type String
82
+ * @default
71
83
  */
72
84
  fontFamily: 'Times New Roman',
73
85
 
74
86
  /**
75
- * Text decoration (e.g. underline, overline)
76
- * @property
87
+ * Text decoration Possible values: "", "underline", "overline" or "line-through".
77
88
  * @type String
89
+ * @default
78
90
  */
79
91
  textDecoration: '',
80
92
 
81
93
  /**
82
94
  * Text shadow
83
- * @property
84
95
  * @type String | null
96
+ * @default
85
97
  */
86
98
  textShadow: '',
87
99
 
88
100
  /**
89
101
  * Text alignment. Possible values: "left", "center", or "right".
90
- * @property
91
102
  * @type String
103
+ * @default
92
104
  */
93
105
  textAlign: 'left',
94
106
 
95
107
  /**
96
- * Font style (e.g. italic)
97
- * @property
108
+ * Font style . Possible values: "", "normal", "italic" or "oblique".
98
109
  * @type String
110
+ * @default
99
111
  */
100
112
  fontStyle: '',
101
113
 
102
114
  /**
103
115
  * Line height
104
- * @property
105
116
  * @type Number
117
+ * @default
106
118
  */
107
119
  lineHeight: 1.3,
108
120
 
109
- /**
110
- * Stroke style. When specified, text is rendered with stroke
111
- * @property
112
- * @type String
113
- */
114
- strokeStyle: '',
115
-
116
- /**
117
- * Stroke width
118
- * @property
119
- * @type Number
120
- */
121
- strokeWidth: 1,
122
-
123
121
  /**
124
122
  * Background color of an entire text box
125
- * @property
126
123
  * @type String
124
+ * @default
127
125
  */
128
126
  backgroundColor: '',
129
127
 
130
128
  /**
131
129
  * Background color of text lines
132
- * @property
133
130
  * @type String
131
+ * @default
134
132
  */
135
133
  textBackgroundColor: '',
136
134
 
137
135
  /**
138
136
  * URL of a font file, when using Cufon
139
- * @property
140
137
  * @type String | null
138
+ * @default
141
139
  */
142
140
  path: null,
143
141
 
144
- /**
145
- * Type of an object
146
- * @property
147
- * @type String
148
- */
149
- type: 'text',
150
-
151
142
  /**
152
143
  * Indicates whether canvas native text methods should be used to render text (otherwise, Cufon is used)
153
- * @property
154
144
  * @type Boolean
145
+ * @default
155
146
  */
156
147
  useNative: true,
157
148
 
158
149
  /**
159
- * List of properties to consider when checking if state of an object is changed (fabric.Object#hasStateChanged)
150
+ * List of properties to consider when checking if state of an object is changed ({@link fabric.Object#hasStateChanged})
160
151
  * as well as for history (undo/redo) purposes
161
- * @property
162
152
  * @type Array
163
153
  */
164
154
  stateProperties: stateProperties,
165
155
 
166
156
  /**
167
157
  * Constructor
168
- * @method initialize
169
- * @param {String} text
170
- * @param {Object} [options]
158
+ * @param {String} text Text string
159
+ * @param {Object} [options] Options object
171
160
  * @return {fabric.Text} thisArg
172
161
  */
173
162
  initialize: function(text, options) {
174
163
  options = options || { };
175
164
 
176
165
  this.text = text;
166
+ this.__skipDimension = true;
177
167
  this.setOptions(options);
168
+ this.__skipDimension = false;
178
169
  this._initDimensions();
179
170
  this.setCoords();
180
171
  },
@@ -182,16 +173,15 @@
182
173
  /**
183
174
  * Renders text object on offscreen canvas, so that it would get dimensions
184
175
  * @private
185
- * @method _initDimensions
186
176
  */
187
177
  _initDimensions: function() {
178
+ if (this.__skipDimension) return;
188
179
  var canvasEl = fabric.util.createCanvasElement();
189
180
  this._render(canvasEl.getContext('2d'));
190
181
  },
191
182
 
192
183
  /**
193
184
  * Returns string representation of an instance
194
- * @method toString
195
185
  * @return {String} String representation of text object
196
186
  */
197
187
  toString: function() {
@@ -201,10 +191,18 @@
201
191
 
202
192
  /**
203
193
  * @private
204
- * @method _render
205
194
  * @param {CanvasRenderingContext2D} ctx Context to render on
206
195
  */
207
196
  _render: function(ctx) {
197
+
198
+ var isInPathGroup = this.group && this.group.type !== 'group';
199
+ if (isInPathGroup && !this.transformMatrix) {
200
+ ctx.translate(-this.group.width/2 + this.left, -this.group.height / 2 + this.top);
201
+ }
202
+ else if (isInPathGroup && this.transformMatrix) {
203
+ ctx.translate(-this.group.width/2, -this.group.height/2);
204
+ }
205
+
208
206
  if (typeof Cufon === 'undefined' || this.useNative === true) {
209
207
  this._renderViaNative(ctx);
210
208
  }
@@ -215,63 +213,12 @@
215
213
 
216
214
  /**
217
215
  * @private
218
- * @method _renderViaCufon
219
- */
220
- _renderViaCufon: function(ctx) {
221
- var o = Cufon.textOptions || (Cufon.textOptions = { });
222
-
223
- // export options to be used by cufon.js
224
- o.left = this.left;
225
- o.top = this.top;
226
- o.context = ctx;
227
- o.color = this.fill;
228
-
229
- var el = this._initDummyElementForCufon();
230
-
231
- // set "cursor" to top/left corner
232
- this.transform(ctx);
233
-
234
- // draw text
235
- Cufon.replaceElement(el, {
236
- engine: 'canvas',
237
- separate: 'none',
238
- fontFamily: this.fontFamily,
239
- fontWeight: this.fontWeight,
240
- textDecoration: this.textDecoration,
241
- textShadow: this.textShadow,
242
- textAlign: this.textAlign,
243
- fontStyle: this.fontStyle,
244
- lineHeight: this.lineHeight,
245
- strokeStyle: this.strokeStyle,
246
- strokeWidth: this.strokeWidth,
247
- backgroundColor: this.backgroundColor,
248
- textBackgroundColor: this.textBackgroundColor
249
- });
250
-
251
- // update width, height
252
- this.width = o.width;
253
- this.height = o.height;
254
-
255
- this._totalLineHeight = o.totalLineHeight;
256
- this._fontAscent = o.fontAscent;
257
- this._boundaries = o.boundaries;
258
- this._shadowOffsets = o.shadowOffsets;
259
- this._shadows = o.shadows || [ ];
260
-
261
- el = null;
262
-
263
- // need to set coords _after_ the width/height was retreived from Cufon
264
- this.setCoords();
265
- },
266
-
267
- /**
268
- * @private
269
- * @method _render_native
270
216
  * @param {CanvasRenderingContext2D} ctx Context to render on
271
217
  */
272
218
  _renderViaNative: function(ctx) {
273
219
 
274
- this.transform(ctx);
220
+ this.transform(ctx, fabric.isLikelyNode);
221
+
275
222
  this._setTextStyles(ctx);
276
223
 
277
224
  var textLines = this.text.split(/\r?\n/);
@@ -286,11 +233,15 @@
286
233
  ctx.translate(this.textAlign === 'center' ? (this.width / 2) : this.width, 0);
287
234
  }
288
235
 
236
+ ctx.save();
289
237
  this._setTextShadow(ctx);
238
+ this.clipTo && fabric.util.clipContext(this, ctx);
290
239
  this._renderTextFill(ctx, textLines);
240
+ this._renderTextStroke(ctx, textLines);
241
+ this.clipTo && ctx.restore();
291
242
  this.textShadow && ctx.restore();
243
+ ctx.restore();
292
244
 
293
- this._renderTextStroke(ctx, textLines);
294
245
  if (this.textAlign !== 'left' && this.textAlign !== 'justify') {
295
246
  ctx.restore();
296
247
  }
@@ -304,7 +255,8 @@
304
255
 
305
256
  /**
306
257
  * @private
307
- * @method _setBoundaries
258
+ * @param {CanvasRenderingContext2D} ctx Context to render on
259
+ * @param {Array} textLines Array of all text lines
308
260
  */
309
261
  _setBoundaries: function(ctx, textLines) {
310
262
  this._boundaries = [ ];
@@ -324,14 +276,23 @@
324
276
 
325
277
  /**
326
278
  * @private
327
- * @method _setTextStyles
279
+ * @param {CanvasRenderingContext2D} ctx Context to render on
328
280
  */
329
281
  _setTextStyles: function(ctx) {
330
- ctx.fillStyle = this.fill.toLive
331
- ? this.fill.toLive(ctx)
332
- : this.fill;
333
- ctx.strokeStyle = this.strokeStyle;
334
- ctx.lineWidth = this.strokeWidth;
282
+ if (this.fill) {
283
+ ctx.fillStyle = this.fill.toLive
284
+ ? this.fill.toLive(ctx)
285
+ : this.fill;
286
+ }
287
+ if (this.stroke) {
288
+ ctx.lineWidth = this.strokeWidth;
289
+ ctx.lineCap = this.strokeLineCap;
290
+ ctx.lineJoin = this.strokeLineJoin;
291
+ ctx.miterLimit = this.strokeMiterLimit;
292
+ ctx.strokeStyle = this.stroke.toLive
293
+ ? this.stroke.toLive(ctx)
294
+ : this.stroke;
295
+ }
335
296
  ctx.textBaseline = 'alphabetic';
336
297
  ctx.textAlign = this.textAlign;
337
298
  ctx.font = this._getFontDeclaration();
@@ -339,7 +300,9 @@
339
300
 
340
301
  /**
341
302
  * @private
342
- * @method _getTextHeight
303
+ * @param {CanvasRenderingContext2D} ctx Context to render on
304
+ * @param {Array} textLines Array of all text lines
305
+ * @return {Number} Height of fabric.Text object
343
306
  */
344
307
  _getTextHeight: function(ctx, textLines) {
345
308
  return this.fontSize * textLines.length * this.lineHeight;
@@ -347,7 +310,9 @@
347
310
 
348
311
  /**
349
312
  * @private
350
- * @method _getTextWidth
313
+ * @param {CanvasRenderingContext2D} ctx Context to render on
314
+ * @param {Array} textLines Array of all text lines
315
+ * @return {Number} Maximum width of fabric.Text object
351
316
  */
352
317
  _getTextWidth: function(ctx, textLines) {
353
318
  var maxWidth = ctx.measureText(textLines[0]).width;
@@ -363,48 +328,46 @@
363
328
 
364
329
  /**
365
330
  * @private
366
- * @method _setTextShadow
331
+ * @param {CanvasRenderingContext2D} ctx Context to render on
367
332
  */
368
333
  _setTextShadow: function(ctx) {
369
- if (this.textShadow) {
334
+ if (!this.textShadow) return;
370
335
 
371
- // "rgba(0,0,0,0.2) 2px 2px 10px"
372
- // "rgb(0, 100, 0) 0 0 5px"
373
- // "red 2px 2px 1px"
374
- // "#f55 123 345 567"
375
- var reOffsetsAndBlur = /\s+(-?\d+)(?:px)?\s+(-?\d+)(?:px)?\s+(\d+)(?:px)?\s*/;
336
+ // "rgba(0,0,0,0.2) 2px 2px 10px"
337
+ // "rgb(0, 100, 0) 0 0 5px"
338
+ // "red 2px 2px 1px"
339
+ // "#f55 123 345 567"
340
+ var reOffsetsAndBlur = /\s+(-?\d+)(?:px)?\s+(-?\d+)(?:px)?\s+(\d+)(?:px)?\s*/;
376
341
 
377
- var shadowDeclaration = this.textShadow;
378
- var offsetsAndBlur = reOffsetsAndBlur.exec(this.textShadow);
379
- var shadowColor = shadowDeclaration.replace(reOffsetsAndBlur, '');
342
+ var shadowDeclaration = this.textShadow;
343
+ var offsetsAndBlur = reOffsetsAndBlur.exec(this.textShadow);
344
+ var shadowColor = shadowDeclaration.replace(reOffsetsAndBlur, '');
380
345
 
381
- ctx.save();
382
- ctx.shadowColor = shadowColor;
383
- ctx.shadowOffsetX = parseInt(offsetsAndBlur[1], 10);
384
- ctx.shadowOffsetY = parseInt(offsetsAndBlur[2], 10);
385
- ctx.shadowBlur = parseInt(offsetsAndBlur[3], 10);
386
-
387
- this._shadows = [{
388
- blur: ctx.shadowBlur,
389
- color: ctx.shadowColor,
390
- offX: ctx.shadowOffsetX,
391
- offY: ctx.shadowOffsetY
392
- }];
393
-
394
- this._shadowOffsets = [[
395
- parseInt(ctx.shadowOffsetX, 10), parseInt(ctx.shadowOffsetY, 10)
396
- ]];
397
- }
346
+ ctx.save();
347
+ ctx.shadowColor = shadowColor;
348
+ ctx.shadowOffsetX = parseInt(offsetsAndBlur[1], 10);
349
+ ctx.shadowOffsetY = parseInt(offsetsAndBlur[2], 10);
350
+ ctx.shadowBlur = parseInt(offsetsAndBlur[3], 10);
351
+
352
+ this._shadows = [{
353
+ blur: ctx.shadowBlur,
354
+ color: ctx.shadowColor,
355
+ offX: ctx.shadowOffsetX,
356
+ offY: ctx.shadowOffsetY
357
+ }];
358
+
359
+ this._shadowOffsets = [[
360
+ parseInt(ctx.shadowOffsetX, 10), parseInt(ctx.shadowOffsetY, 10)
361
+ ]];
398
362
  },
399
363
 
400
364
  /**
401
365
  * @private
402
- * @method _drawTextLine
403
- * @param method
404
- * @param ctx
405
- * @param line
406
- * @param left
407
- * param top
366
+ * @param {String} method Method name ("fillText" or "strokeText")
367
+ * @param {CanvasRenderingContext2D} ctx Context to render on
368
+ * @param {String} line Text to render
369
+ * @param {Number} left Left position of text
370
+ * @param {Number} top Top position of text
408
371
  */
409
372
  _drawTextLine: function(method, ctx, line, left, top) {
410
373
 
@@ -439,44 +402,88 @@
439
402
 
440
403
  /**
441
404
  * @private
442
- * @method _renderTextFill
405
+ * @return {Number} Left offset
406
+ */
407
+ _getLeftOffset: function() {
408
+ if (fabric.isLikelyNode && (this.originX === 'left' || this.originX === 'center')) {
409
+ return 0;
410
+ }
411
+ return -this.width / 2;
412
+ },
413
+
414
+ /**
415
+ * @private
416
+ * @return {Number} Top offset
417
+ */
418
+ _getTopOffset: function() {
419
+ if (fabric.isLikelyNode) {
420
+ if (this.originY === 'center') {
421
+ return -this.height / 2;
422
+ }
423
+ else if (this.originY === 'bottom') {
424
+ return -this.height;
425
+ }
426
+ return 0;
427
+ }
428
+ // in browser, text drawing always starts at vertical center
429
+ return -this.height / 2;
430
+ },
431
+
432
+ /**
433
+ * @private
434
+ * @param {CanvasRenderingContext2D} ctx Context to render on
435
+ * @param {Array} textLines Array of all text lines
443
436
  */
444
437
  _renderTextFill: function(ctx, textLines) {
438
+ if (!this.fill) return;
439
+
445
440
  this._boundaries = [ ];
446
441
  for (var i = 0, len = textLines.length; i < len; i++) {
447
442
  this._drawTextLine(
448
443
  'fillText',
449
444
  ctx,
450
445
  textLines[i],
451
- -this.width / 2,
452
- (-this.height / 2) + (i * this.fontSize * this.lineHeight) + this.fontSize
446
+ this._getLeftOffset(),
447
+ this._getTopOffset() + (i * this.fontSize * this.lineHeight) + this.fontSize
453
448
  );
454
449
  }
455
450
  },
456
451
 
457
452
  /**
458
453
  * @private
459
- * @method _renderTextStroke
454
+ * @param {CanvasRenderingContext2D} ctx Context to render on
455
+ * @param {Array} textLines Array of all text lines
460
456
  */
461
457
  _renderTextStroke: function(ctx, textLines) {
462
- if (this.strokeStyle) {
463
- ctx.beginPath();
464
- for (var i = 0, len = textLines.length; i < len; i++) {
465
- this._drawTextLine(
466
- 'strokeText',
467
- ctx,
468
- textLines[i],
469
- -this.width / 2,
470
- (-this.height / 2) + (i * this.fontSize * this.lineHeight) + this.fontSize
471
- );
458
+ if (!this.stroke) return;
459
+
460
+ ctx.save();
461
+ if (this.strokeDashArray) {
462
+ // Spec requires the concatenation of two copies the dash list when the number of elements is odd
463
+ if (1 & this.strokeDashArray.length) {
464
+ this.strokeDashArray.push.apply(this.strokeDashArray, this.strokeDashArray);
472
465
  }
473
- ctx.closePath();
466
+ supportsLineDash && ctx.setLineDash(this.strokeDashArray);
474
467
  }
468
+
469
+ ctx.beginPath();
470
+ for (var i = 0, len = textLines.length; i < len; i++) {
471
+ this._drawTextLine(
472
+ 'strokeText',
473
+ ctx,
474
+ textLines[i],
475
+ this._getLeftOffset(),
476
+ this._getTopOffset() + (i * this.fontSize * this.lineHeight) + this.fontSize
477
+ );
478
+ }
479
+ ctx.closePath();
480
+ ctx.restore();
475
481
  },
476
482
 
477
483
  /**
478
484
  * @private
479
- * @method _renderTextBackground
485
+ * @param {CanvasRenderingContext2D} ctx Context to render on
486
+ * @param {Array} textLines Array of all text lines
480
487
  */
481
488
  _renderTextBackground: function(ctx, textLines) {
482
489
  this._renderTextBoxBackground(ctx);
@@ -485,55 +492,57 @@
485
492
 
486
493
  /**
487
494
  * @private
488
- * @method _renderTextBoxBackground
495
+ * @param {CanvasRenderingContext2D} ctx Context to render on
489
496
  */
490
497
  _renderTextBoxBackground: function(ctx) {
491
- if (this.backgroundColor) {
492
- ctx.save();
493
- ctx.fillStyle = this.backgroundColor;
498
+ if (!this.backgroundColor) return;
494
499
 
495
- ctx.fillRect(
496
- (-this.width / 2),
497
- (-this.height / 2),
498
- this.width,
499
- this.height
500
- );
500
+ ctx.save();
501
+ ctx.fillStyle = this.backgroundColor;
501
502
 
502
- ctx.restore();
503
- }
503
+ ctx.fillRect(
504
+ this._getLeftOffset(),
505
+ this._getTopOffset(),
506
+ this.width,
507
+ this.height
508
+ );
509
+
510
+ ctx.restore();
504
511
  },
505
512
 
506
513
  /**
507
514
  * @private
508
- * @method _renderTextLinesBackground
515
+ * @param {CanvasRenderingContext2D} ctx Context to render on
516
+ * @param {Array} textLines Array of all text lines
509
517
  */
510
518
  _renderTextLinesBackground: function(ctx, textLines) {
511
- if (this.textBackgroundColor) {
512
- ctx.save();
513
- ctx.fillStyle = this.textBackgroundColor;
519
+ if (!this.textBackgroundColor) return;
514
520
 
515
- for (var i = 0, len = textLines.length; i < len; i++) {
521
+ ctx.save();
522
+ ctx.fillStyle = this.textBackgroundColor;
516
523
 
517
- if (textLines[i] !== '') {
524
+ for (var i = 0, len = textLines.length; i < len; i++) {
518
525
 
519
- var lineWidth = this._getLineWidth(ctx, textLines[i]);
520
- var lineLeftOffset = this._getLineLeftOffset(lineWidth);
526
+ if (textLines[i] !== '') {
521
527
 
522
- ctx.fillRect(
523
- (-this.width / 2) + lineLeftOffset,
524
- (-this.height / 2) + (i * this.fontSize * this.lineHeight),
525
- lineWidth,
526
- this.fontSize * this.lineHeight
527
- );
528
- }
528
+ var lineWidth = this._getLineWidth(ctx, textLines[i]);
529
+ var lineLeftOffset = this._getLineLeftOffset(lineWidth);
530
+
531
+ ctx.fillRect(
532
+ this._getLeftOffset() + lineLeftOffset,
533
+ this._getTopOffset() + (i * this.fontSize * this.lineHeight),
534
+ lineWidth,
535
+ this.fontSize * this.lineHeight
536
+ );
529
537
  }
530
- ctx.restore();
531
538
  }
539
+ ctx.restore();
532
540
  },
533
541
 
534
542
  /**
535
543
  * @private
536
- * @method _getLineLeftOffset
544
+ * @param {Number} lineWidth Width of text line
545
+ * @return {Number} Line left offset
537
546
  */
538
547
  _getLineLeftOffset: function(lineWidth) {
539
548
  if (this.textAlign === 'center') {
@@ -547,9 +556,9 @@
547
556
 
548
557
  /**
549
558
  * @private
550
- * @method _getLineWidth
551
- * @param ctx
552
- * @param line
559
+ * @param {CanvasRenderingContext2D} ctx Context to render on
560
+ * @param {String} line Text line
561
+ * @return {Number} Line width
553
562
  */
554
563
  _getLineWidth: function(ctx, line) {
555
564
  return this.textAlign === 'justify'
@@ -559,11 +568,13 @@
559
568
 
560
569
  /**
561
570
  * @private
562
- * @method _renderTextDecoration
571
+ * @param {CanvasRenderingContext2D} ctx Context to render on
572
+ * @param {Array} textLines Array of all text lines
563
573
  */
564
574
  _renderTextDecoration: function(ctx, textLines) {
575
+ if (!this.textDecoration) return;
565
576
 
566
- var halfOfVerticalBox = this._getTextHeight(ctx, textLines) / 2;
577
+ var halfOfVerticalBox = this.originY === 'top' ? 0 : this._getTextHeight(ctx, textLines) / 2;
567
578
  var _this = this;
568
579
 
569
580
  /** @ignore */
@@ -574,7 +585,7 @@
574
585
  var lineLeftOffset = _this._getLineLeftOffset(lineWidth);
575
586
 
576
587
  ctx.fillRect(
577
- (-_this.width / 2) + lineLeftOffset,
588
+ _this._getLeftOffset() + lineLeftOffset,
578
589
  (offset + (i * _this.fontSize * _this.lineHeight)) - halfOfVerticalBox,
579
590
  lineWidth,
580
591
  1);
@@ -594,7 +605,6 @@
594
605
 
595
606
  /**
596
607
  * @private
597
- * @method _getFontDeclaration
598
608
  */
599
609
  _getFontDeclaration: function() {
600
610
  return [
@@ -606,39 +616,15 @@
606
616
  ].join(' ');
607
617
  },
608
618
 
609
- /**
610
- * @private
611
- * @method _initDummyElement
612
- */
613
- _initDummyElementForCufon: function() {
614
- var el = fabric.document.createElement('pre'),
615
- container = fabric.document.createElement('div');
616
-
617
- // Cufon doesn't play nice with textDecoration=underline if element doesn't have a parent
618
- container.appendChild(el);
619
-
620
- if (typeof G_vmlCanvasManager === 'undefined') {
621
- el.innerHTML = this.text;
622
- }
623
- else {
624
- // IE 7 & 8 drop newlines and white space on text nodes
625
- // see: http://web.student.tuwien.ac.at/~e0226430/innerHtmlQuirk.html
626
- // see: http://www.w3schools.com/dom/dom_mozilla_vs_ie.asp
627
- el.innerText = this.text.replace(/\r?\n/gi, '\r');
628
- }
629
-
630
- el.style.fontSize = this.fontSize + 'px';
631
- el.style.letterSpacing = 'normal';
632
-
633
- return el;
634
- },
635
-
636
619
  /**
637
620
  * Renders text instance on a specified context
638
- * @method render
639
- * @param ctx {CanvasRenderingContext2D} context to render on
621
+ * @param {CanvasRenderingContext2D} ctx Context to render on
622
+ * @param {Boolean} [noTransform] When true, context is not transformed
640
623
  */
641
624
  render: function(ctx, noTransform) {
625
+ // do not render if object is not visible
626
+ if (!this.visible) return;
627
+
642
628
  ctx.save();
643
629
  this._render(ctx);
644
630
  if (!noTransform && this.active) {
@@ -650,9 +636,8 @@
650
636
 
651
637
  /**
652
638
  * Returns object representation of an instance
653
- * @method toObject
654
- * @param {Array} propertiesToInclude
655
- * @return {Object} object representation of an instance
639
+ * @param {Array} [propertiesToInclude] Any properties that you might want to additionally include in the output
640
+ * @return {Object} Object representation of an instance
656
641
  */
657
642
  toObject: function(propertiesToInclude) {
658
643
  return extend(this.callSuper('toObject', propertiesToInclude), {
@@ -666,17 +651,15 @@
666
651
  textShadow: this.textShadow,
667
652
  textAlign: this.textAlign,
668
653
  path: this.path,
669
- strokeStyle: this.strokeStyle,
670
- strokeWidth: this.strokeWidth,
671
654
  backgroundColor: this.backgroundColor,
672
655
  textBackgroundColor: this.textBackgroundColor,
673
656
  useNative: this.useNative
674
657
  });
675
658
  },
676
659
 
660
+ /* _TO_SVG_START_ */
677
661
  /**
678
662
  * Returns SVG representation of an instance
679
- * @method toSVG
680
663
  * @return {String} svg representation of an instance
681
664
  */
682
665
  toSVG: function() {
@@ -718,7 +701,9 @@
718
701
 
719
702
  /**
720
703
  * @private
721
- * @method _getSVGShadows
704
+ * @param {Number} lineTopOffset Line top offset
705
+ * @param {Array} textLines Array of all text lines
706
+ * @return {Array}
722
707
  */
723
708
  _getSVGShadows: function(lineTopOffset, textLines) {
724
709
  var shadowSpans = [], j, i, jlen, ilen, lineTopOffsetMultiplier = 1;
@@ -755,7 +740,10 @@
755
740
 
756
741
  /**
757
742
  * @private
758
- * @method _getSVGTextAndBg
743
+ * @param {Number} lineTopOffset Line top offset
744
+ * @param {Number} textLeftOffset Text left offset
745
+ * @param {Array} textLines Array of all text lines
746
+ * @return {Object}
759
747
  */
760
748
  _getSVGTextAndBg: function(lineTopOffset, textLeftOffset, textLines) {
761
749
  var textSpans = [ ], textBgRects = [ ], i, lineLeftOffset, len, lineTopOffsetMultiplier = 1;
@@ -825,19 +813,20 @@
825
813
  * we work around it by "moving" alpha channel into opacity attribute and setting fill's alpha to 1
826
814
  *
827
815
  * @private
828
- * @method _getFillAttributes
816
+ * @param {Any} value
817
+ * @return {String}
829
818
  */
830
819
  _getFillAttributes: function(value) {
831
- var fillColor = value ? new fabric.Color(value) : '';
820
+ var fillColor = (value && typeof value === 'string') ? new fabric.Color(value) : '';
832
821
  if (!fillColor || !fillColor.getSource() || fillColor.getAlpha() === 1) {
833
822
  return 'fill="' + value + '"';
834
823
  }
835
824
  return 'opacity="' + fillColor.getAlpha() + '" fill="' + fillColor.setAlpha(1).toRgb() + '"';
836
825
  },
826
+ /* _TO_SVG_END_ */
837
827
 
838
828
  /**
839
829
  * Sets "color" of an instance (alias of `set('fill', &hellip;)`)
840
- * @method setColor
841
830
  * @param {String} value
842
831
  * @return {fabric.Text} thisArg
843
832
  * @chainable
@@ -849,7 +838,6 @@
849
838
 
850
839
  /**
851
840
  * Returns actual text value of an instance
852
- * @method getText
853
841
  * @return {String}
854
842
  */
855
843
  getText: function() {
@@ -858,7 +846,6 @@
858
846
 
859
847
  /**
860
848
  * Sets specified property to a specified value
861
- * @method set
862
849
  * @param {String} name
863
850
  * @param {Any} value
864
851
  * @return {fabric.Text} thisArg
@@ -870,39 +857,35 @@
870
857
  }
871
858
  this.callSuper('_set', name, value);
872
859
 
873
- if (name in dimensionAffectingProps) {
860
+ if (name in this._dimensionAffectingProps) {
874
861
  this._initDimensions();
875
862
  this.setCoords();
876
863
  }
864
+ },
865
+
866
+ /**
867
+ * Returns complexity of an instance
868
+ * @return {Number} complexity
869
+ */
870
+ complexity: function() {
871
+ return 1;
877
872
  }
878
873
  });
879
874
 
875
+ /* _FROM_SVG_START_ */
880
876
  /**
881
877
  * List of attribute names to account for when parsing SVG element (used by {@link fabric.Text.fromElement})
882
878
  * @static
883
879
  */
884
- fabric.Text.ATTRIBUTE_NAMES =
885
- ('x y fill fill-opacity opacity stroke stroke-width transform ' +
886
- 'font-family font-style font-weight font-size text-decoration').split(' ');
887
-
888
- /**
889
- * Returns fabric.Text instance from an object representation
890
- * @static
891
- * @method fromObject
892
- * @param {Object} object to create an instance from
893
- * @return {fabric.Text} an instance
894
- */
895
- fabric.Text.fromObject = function(object) {
896
- return new fabric.Text(object.text, clone(object));
897
- };
880
+ fabric.Text.ATTRIBUTE_NAMES = fabric.SHARED_ATTRIBUTES.concat(
881
+ 'x y font-family font-style font-weight font-size text-decoration'.split(' '));
898
882
 
899
883
  /**
900
884
  * Returns fabric.Text instance from an SVG element (<b>not yet implemented</b>)
901
885
  * @static
902
- * @method fabric.Text.fromElement
903
- * @param element
904
- * @param options
905
- * @return {fabric.Text} an instance
886
+ * @param {SVGElement} element Element to parse
887
+ * @param {Object} [options] Options object
888
+ * @return {fabric.Text} Instance of fabric.Text
906
889
  */
907
890
  fabric.Text.fromElement = function(element, options) {
908
891
 
@@ -928,7 +911,18 @@
928
911
 
929
912
  return text;
930
913
  };
914
+ /* _FROM_SVG_END_ */
915
+
916
+ /**
917
+ * Returns fabric.Text instance from an object representation
918
+ * @static
919
+ * @param object {Object} object Object to create an instance from
920
+ * @return {fabric.Text} Instance of fabric.Text
921
+ */
922
+ fabric.Text.fromObject = function(object) {
923
+ return new fabric.Text(object.text, clone(object));
924
+ };
931
925
 
932
926
  fabric.util.createAccessors(fabric.Text);
933
927
 
934
- })(typeof exports !== 'undefined' ? exports : this);
928
+ })(typeof exports !== 'undefined' ? exports : this);