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
@@ -15,15 +15,15 @@
15
15
 
16
16
  /**
17
17
  * Image class
18
- * @class Image
18
+ * @class fabric.Image
19
19
  * @extends fabric.Object
20
20
  */
21
- fabric.Image = fabric.util.createClass(fabric.Object, /** @scope fabric.Image.prototype */ {
21
+ fabric.Image = fabric.util.createClass(fabric.Object, /** @lends fabric.Image.prototype */ {
22
22
 
23
23
  /**
24
24
  * Type of an object
25
- * @property
26
25
  * @type String
26
+ * @default
27
27
  */
28
28
  type: 'image',
29
29
 
@@ -31,7 +31,7 @@
31
31
  * Constructor
32
32
  * @param {HTMLImageElement | String} element Image element
33
33
  * @param {Object} [options] Options object
34
- * @return {fabric.Image}
34
+ * @return {fabric.Image} thisArg
35
35
  */
36
36
  initialize: function(element, options) {
37
37
  options || (options = { });
@@ -51,8 +51,7 @@
51
51
 
52
52
  /**
53
53
  * Returns image element which this instance if based on
54
- * @method getElement
55
- * @return {HTMLImageElement} image element
54
+ * @return {HTMLImageElement} Image element
56
55
  */
57
56
  getElement: function() {
58
57
  return this._element;
@@ -60,7 +59,6 @@
60
59
 
61
60
  /**
62
61
  * Sets image element for this instance to a specified one
63
- * @method setElement
64
62
  * @param {HTMLImageElement} element
65
63
  * @return {fabric.Image} thisArg
66
64
  * @chainable
@@ -73,7 +71,6 @@
73
71
 
74
72
  /**
75
73
  * Returns original size of an image
76
- * @method getOriginalSize
77
74
  * @return {Object} object with "width" and "height" properties
78
75
  */
79
76
  getOriginalSize: function() {
@@ -86,14 +83,19 @@
86
83
 
87
84
  /**
88
85
  * Renders image on a specified context
89
- * @method render
90
86
  * @param {CanvasRenderingContext2D} ctx Context to render on
87
+ * @param {Boolean} [noTransform] When true, context is not transformed
91
88
  */
92
89
  render: function(ctx, noTransform) {
90
+ // do not render if object is not visible
91
+ if (!this.visible) return;
92
+
93
93
  ctx.save();
94
94
  var m = this.transformMatrix;
95
+ var isInPathGroup = this.group && this.group.type !== 'group';
96
+
95
97
  // this._resetWidthHeight();
96
- if (this.group) {
98
+ if (isInPathGroup) {
97
99
  ctx.translate(-this.group.width/2 + this.width/2, -this.group.height/2 + this.height/2);
98
100
  }
99
101
  if (m) {
@@ -103,9 +105,16 @@
103
105
  this.transform(ctx);
104
106
  }
105
107
 
108
+ ctx.save();
106
109
  this._setShadow(ctx);
110
+ this.clipTo && fabric.util.clipContext(this, ctx);
107
111
  this._render(ctx);
108
- this._removeShadow(ctx);
112
+ if (this.shadow && !this.shadow.affectStroke) {
113
+ this._removeShadow(ctx);
114
+ }
115
+ this._renderStroke(ctx);
116
+ this.clipTo && ctx.restore();
117
+ ctx.restore();
109
118
 
110
119
  if (this.active && !noTransform) {
111
120
  this.drawBorders(ctx);
@@ -114,11 +123,58 @@
114
123
  ctx.restore();
115
124
  },
116
125
 
126
+ /**
127
+ * @private
128
+ * @param {CanvasRenderingContext2D} ctx Context to render on
129
+ */
130
+ _stroke: function(ctx) {
131
+ ctx.save();
132
+ ctx.lineWidth = this.strokeWidth;
133
+ ctx.lineCap = this.strokeLineCap;
134
+ ctx.lineJoin = this.strokeLineJoin;
135
+ ctx.miterLimit = this.strokeMiterLimit;
136
+ ctx.strokeStyle = this.stroke.toLive
137
+ ? this.stroke.toLive(ctx)
138
+ : this.stroke;
139
+
140
+ ctx.beginPath();
141
+ ctx.strokeRect(-this.width / 2, -this.height / 2, this.width, this.height);
142
+ ctx.closePath();
143
+ ctx.restore();
144
+ },
145
+
146
+ /**
147
+ * @private
148
+ * @param {CanvasRenderingContext2D} ctx Context to render on
149
+ */
150
+ _renderDashedStroke: function(ctx) {
151
+ var x = -this.width/2,
152
+ y = -this.height/2,
153
+ w = this.width,
154
+ h = this.height;
155
+
156
+ ctx.save();
157
+ ctx.lineWidth = this.strokeWidth;
158
+ ctx.lineCap = this.strokeLineCap;
159
+ ctx.lineJoin = this.strokeLineJoin;
160
+ ctx.miterLimit = this.strokeMiterLimit;
161
+ ctx.strokeStyle = this.stroke.toLive
162
+ ? this.stroke.toLive(ctx)
163
+ : this.stroke;
164
+
165
+ ctx.beginPath();
166
+ fabric.util.drawDashedLine(ctx, x, y, x+w, y, this.strokeDashArray);
167
+ fabric.util.drawDashedLine(ctx, x+w, y, x+w, y+h, this.strokeDashArray);
168
+ fabric.util.drawDashedLine(ctx, x+w, y+h, x, y+h, this.strokeDashArray);
169
+ fabric.util.drawDashedLine(ctx, x, y+h, x, y, this.strokeDashArray);
170
+ ctx.closePath();
171
+ ctx.restore();
172
+ },
173
+
117
174
  /**
118
175
  * Returns object representation of an instance
119
- * @method toObject
120
176
  * @param {Array} propertiesToInclude
121
- * @return {Object} object representation of an instance
177
+ * @return {Object} propertiesToInclude Object representation of an instance
122
178
  */
123
179
  toObject: function(propertiesToInclude) {
124
180
  return extend(this.callSuper('toObject', propertiesToInclude), {
@@ -127,27 +183,48 @@
127
183
  });
128
184
  },
129
185
 
186
+ /* _TO_SVG_START_ */
130
187
  /**
131
188
  * Returns SVG representation of an instance
132
- * @method toSVG
133
189
  * @return {String} svg representation of an instance
134
190
  */
135
191
  toSVG: function() {
136
- return '<g transform="' + this.getSvgTransform() + '">'+
137
- '<image xlink:href="' + this.getSvgSrc() + '" '+
138
- 'style="' + this.getSvgStyles() + '" ' +
139
- // we're essentially moving origin of transformation from top/left corner to the center of the shape
140
- // by wrapping it in container <g> element with actual transformation, then offsetting object to the top/left
141
- // so that object's center aligns with container's left/top
142
- 'transform="translate('+ (-this.width/2) + ' ' + (-this.height/2) + ')" ' +
143
- 'width="' + this.width + '" ' +
144
- 'height="' + this.height + '"' + '></image>' +
145
- '</g>';
192
+ var markup = [];
193
+
194
+ markup.push(
195
+ '<g transform="', this.getSvgTransform(), '">',
196
+ '<image xlink:href="', this.getSvgSrc(),
197
+ '" style="', this.getSvgStyles(),
198
+ // we're essentially moving origin of transformation from top/left corner to the center of the shape
199
+ // by wrapping it in container <g> element with actual transformation, then offsetting object to the top/left
200
+ // so that object's center aligns with container's left/top
201
+ '" transform="translate(' + (-this.width/2) + ' ' + (-this.height/2) + ')',
202
+ '" width="', this.width,
203
+ '" height="', this.height,
204
+ '"></image>'
205
+ );
206
+
207
+ if (this.stroke || this.strokeDashArray) {
208
+ var origFill = this.fill;
209
+ this.fill = null;
210
+ markup.push(
211
+ '<rect ',
212
+ 'x="', (-1 * this.width / 2), '" y="', (-1 * this.height / 2),
213
+ '" width="', this.width, '" height="', this.height,
214
+ '" style="', this.getSvgStyles(),
215
+ '"/>'
216
+ );
217
+ this.fill = origFill;
218
+ }
219
+
220
+ markup.push('</g>');
221
+
222
+ return markup.join('');
146
223
  },
224
+ /* _TO_SVG_END_ */
147
225
 
148
226
  /**
149
227
  * Returns source of an image
150
- * @method getSrc
151
228
  * @return {String} Source of an image
152
229
  */
153
230
  getSrc: function() {
@@ -156,7 +233,6 @@
156
233
 
157
234
  /**
158
235
  * Returns string representation of an instance
159
- * @method toString
160
236
  * @return {String} String representation of an instance
161
237
  */
162
238
  toString: function() {
@@ -165,9 +241,8 @@
165
241
 
166
242
  /**
167
243
  * Returns a clone of an instance
168
- * @method clone
169
- * @param {Array} propertiesToInclude
170
244
  * @param {Function} callback Callback is invoked with a clone as a first argument
245
+ * @param {Array} propertiesToInclude
171
246
  */
172
247
  clone: function(callback, propertiesToInclude) {
173
248
  this.constructor.fromObject(this.toObject(propertiesToInclude), callback);
@@ -188,10 +263,9 @@
188
263
  return;
189
264
  }
190
265
 
191
- var isLikelyNode = typeof Buffer !== 'undefined' && typeof window === 'undefined',
192
- imgEl = this._originalImage,
266
+ var imgEl = this._originalImage,
193
267
  canvasEl = fabric.util.createCanvasElement(),
194
- replacement = isLikelyNode ? new (require('canvas').Image)() : fabric.document.createElement('img'),
268
+ replacement = fabric.util.createImage(),
195
269
  _this = this;
196
270
 
197
271
  canvasEl.width = imgEl.width;
@@ -204,24 +278,25 @@
204
278
  });
205
279
 
206
280
  /** @ignore */
207
- replacement.onload = function() {
208
- _this._element = replacement;
209
- callback && callback();
210
- replacement.onload = canvasEl = imgEl = null;
211
- };
281
+
212
282
  replacement.width = imgEl.width;
213
283
  replacement.height = imgEl.height;
214
284
 
215
- if (isLikelyNode) {
285
+ if (fabric.isLikelyNode) {
216
286
  // cut off data:image/png;base64, part in the beginning
217
287
  var base64str = canvasEl.toDataURL('image/png').substring(22);
218
288
  replacement.src = new Buffer(base64str, 'base64');
219
- _this._element = replacement;
220
289
 
221
- // onload doesn't fire in node, so we invoke callback manually
290
+ // onload doesn't fire in some node versions, so we invoke callback manually
291
+ _this._element = replacement;
222
292
  callback && callback();
223
293
  }
224
294
  else {
295
+ replacement.onload = function() {
296
+ _this._element = replacement;
297
+ callback && callback();
298
+ replacement.onload = canvasEl = imgEl = null;
299
+ };
225
300
  replacement.src = canvasEl.toDataURL('image/png');
226
301
  }
227
302
 
@@ -230,7 +305,6 @@
230
305
 
231
306
  /**
232
307
  * @private
233
- * @method _render
234
308
  * @param ctx
235
309
  */
236
310
  _render: function(ctx) {
@@ -245,7 +319,6 @@
245
319
 
246
320
  /**
247
321
  * @private
248
- * @method _resetWidthHeight
249
322
  */
250
323
  _resetWidthHeight: function() {
251
324
  var element = this.getElement();
@@ -258,7 +331,6 @@
258
331
  * The Image class's initialization method. This method is automatically
259
332
  * called by the constructor.
260
333
  * @private
261
- * @method _initElement
262
334
  * @param {HTMLImageElement|String} el The element representing the image
263
335
  */
264
336
  _initElement: function(element) {
@@ -268,7 +340,6 @@
268
340
 
269
341
  /**
270
342
  * @private
271
- * @method _initConfig
272
343
  * @param {Object} [options] Options object
273
344
  */
274
345
  _initConfig: function(options) {
@@ -279,7 +350,6 @@
279
350
 
280
351
  /**
281
352
  * @private
282
- * @method _initFilters
283
353
  * @param {Object} object Object with filters property
284
354
  */
285
355
  _initFilters: function(object) {
@@ -292,7 +362,6 @@
292
362
 
293
363
  /**
294
364
  * @private
295
- * @method _setWidthHeight
296
365
  * @param {Object} [options] Object with width/height properties
297
366
  */
298
367
  _setWidthHeight: function(options) {
@@ -307,8 +376,7 @@
307
376
 
308
377
  /**
309
378
  * Returns complexity of an instance
310
- * @method complexity
311
- * @return {Number} complexity
379
+ * @return {Number} complexity of this instance
312
380
  */
313
381
  complexity: function() {
314
382
  return 1;
@@ -325,14 +393,12 @@
325
393
  /**
326
394
  * Alias for getSrc
327
395
  * @static
328
- * @method getSvgSrc
329
396
  */
330
397
  fabric.Image.prototype.getSvgSrc = fabric.Image.prototype.getSrc;
331
398
 
332
399
  /**
333
400
  * Creates an instance of fabric.Image from its object representation
334
401
  * @static
335
- * @method fromObject
336
402
  * @param {Object} object
337
403
  * @param {Function} [callback] Callback to invoke when an image instance is created
338
404
  */
@@ -343,6 +409,7 @@
343
409
  if (object.width) {
344
410
  img.width = object.width;
345
411
  }
412
+
346
413
  if (object.height) {
347
414
  img.height = object.height;
348
415
  }
@@ -353,60 +420,55 @@
353
420
 
354
421
  var instance = new fabric.Image(img, object);
355
422
  callback && callback(instance);
356
- img = img.onload = img.onerror = null;
357
- };
423
+ img = img.onload = img.onerror = null;
424
+ };
425
+
426
+ /** @ignore */
427
+ img.onerror = function() {
428
+ fabric.log('Error loading ' + img.src);
429
+ callback && callback(null, true);
430
+ img = img.onload = img.onerror = null;
431
+ };
358
432
 
359
- /** @ignore */
360
- img.onerror = function() {
361
- fabric.log('Error loading ' + img.src);
362
- callback && callback(null, true);
363
- img = img.onload = img.onerror = null;
364
- };
365
433
  img.src = src;
366
434
  };
367
435
 
368
436
  /**
369
437
  * Creates an instance of fabric.Image from an URL string
370
438
  * @static
371
- * @method fromURL
372
439
  * @param {String} url URL to create an image from
373
440
  * @param {Function} [callback] Callback to invoke when image is created (newly created image is passed as a first argument)
374
441
  * @param {Object} [imgOptions] Options object
375
442
  */
376
443
  fabric.Image.fromURL = function(url, callback, imgOptions) {
377
- var img = fabric.document.createElement('img');
378
-
379
- /** @ignore */
380
- img.onload = function() {
381
- if (callback) {
382
- callback(new fabric.Image(img, imgOptions));
383
- }
384
- img = img.onload = null;
385
- };
386
- img.src = url;
444
+ fabric.util.loadImage(url, function(img) {
445
+ callback(new fabric.Image(img, imgOptions));
446
+ });
387
447
  };
388
448
 
449
+ /* _FROM_SVG_START_ */
389
450
  /**
390
451
  * List of attribute names to account for when parsing SVG element (used by {@link fabric.Image.fromElement})
391
452
  * @static
392
453
  * @see http://www.w3.org/TR/SVG/struct.html#ImageElement
393
454
  */
394
- fabric.Image.ATTRIBUTE_NAMES = 'x y width height fill fill-opacity opacity stroke stroke-width transform xlink:href'.split(' ');
455
+ fabric.Image.ATTRIBUTE_NAMES = fabric.SHARED_ATTRIBUTES.concat('x y width height xlink:href'.split(' '));
395
456
 
396
457
  /**
397
458
  * Returns {@link fabric.Image} instance from an SVG element
398
459
  * @static
399
- * @method fabric.Image.fromElement
400
460
  * @param {SVGElement} element Element to parse
401
461
  * @param {Function} callback Callback to execute when fabric.Image object is created
402
462
  * @param {Object} [options] Options object
403
- * @return {fabric.Image}
463
+ * @return {fabric.Image} Instance of fabric.Image
404
464
  */
405
465
  fabric.Image.fromElement = function(element, callback, options) {
406
466
  var parsedAttributes = fabric.parseAttributes(element, fabric.Image.ATTRIBUTE_NAMES);
407
467
 
408
- fabric.Image.fromURL(parsedAttributes['xlink:href'], callback, extend((options ? fabric.util.object.clone(options) : { }), parsedAttributes));
468
+ fabric.Image.fromURL(parsedAttributes['xlink:href'], callback,
469
+ extend((options ? fabric.util.object.clone(options) : { }), parsedAttributes));
409
470
  };
471
+ /* _FROM_SVG_END_ */
410
472
 
411
473
  /**
412
474
  * Indicates that instances of this type are async
@@ -4,7 +4,8 @@
4
4
 
5
5
  var fabric = global.fabric || (global.fabric = { }),
6
6
  extend = fabric.util.object.extend,
7
- coordProps = { 'x1': 1, 'x2': 1, 'y1': 1, 'y2': 1 };
7
+ coordProps = { 'x1': 1, 'x2': 1, 'y1': 1, 'y2': 1 },
8
+ supportsLineDash = fabric.StaticCanvas.supports('setLineDash');
8
9
 
9
10
  if (fabric.Line) {
10
11
  fabric.warn('fabric.Line is already defined');
@@ -13,21 +14,20 @@
13
14
 
14
15
  /**
15
16
  * Line class
16
- * @class Line
17
+ * @class fabric.Line
17
18
  * @extends fabric.Object
18
19
  */
19
- fabric.Line = fabric.util.createClass(fabric.Object, /** @scope fabric.Line.prototype */ {
20
+ fabric.Line = fabric.util.createClass(fabric.Object, /** @lends fabric.Line.prototype */ {
20
21
 
21
22
  /**
22
23
  * Type of an object
23
- * @property
24
24
  * @type String
25
+ * @default
25
26
  */
26
27
  type: 'line',
27
28
 
28
29
  /**
29
30
  * Constructor
30
- * @method initialize
31
31
  * @param {Array} [points] Array of points
32
32
  * @param {Object} [options] Options object
33
33
  * @return {fabric.Line} thisArg
@@ -51,22 +51,20 @@
51
51
 
52
52
  /**
53
53
  * @private
54
- * @method _setWidthHeight
55
54
  * @param {Object} [options] Options
56
55
  */
57
56
  _setWidthHeight: function(options) {
58
57
  options || (options = { });
59
58
 
60
- this.set('width', (this.x2 - this.x1) || 1);
61
- this.set('height', (this.y2 - this.y1) || 1);
59
+ this.set('width', Math.abs(this.x2 - this.x1) || 1);
60
+ this.set('height', Math.abs(this.y2 - this.y1) || 1);
62
61
 
63
- this.set('left', 'left' in options ? options.left : (this.x1 + this.width / 2));
64
- this.set('top', 'top' in options ? options.top : (this.y1 + this.height / 2));
62
+ this.set('left', 'left' in options ? options.left : (Math.min(this.x1, this.x2) + this.width / 2));
63
+ this.set('top', 'top' in options ? options.top : (Math.min(this.y1, this.y2) + this.height / 2));
65
64
  },
66
65
 
67
66
  /**
68
67
  * @private
69
- * @method _set
70
68
  * @param {String} key
71
69
  * @param {Any} value
72
70
  */
@@ -80,19 +78,31 @@
80
78
 
81
79
  /**
82
80
  * @private
83
- * @method _render
84
81
  * @param {CanvasRenderingContext2D} ctx Context to render on
85
82
  */
86
83
  _render: function(ctx) {
87
84
  ctx.beginPath();
88
85
 
89
- if (this.group) {
86
+ var isInPathGroup = this.group && this.group.type !== 'group';
87
+ if (isInPathGroup && !this.transformMatrix) {
90
88
  ctx.translate(-this.group.width/2 + this.left, -this.group.height / 2 + this.top);
91
89
  }
92
90
 
93
- // move from center (of virtual box) to its left/top corner
94
- ctx.moveTo(this.width === 1 ? 0 : (-this.width / 2), this.height === 1 ? 0 : (-this.height / 2));
95
- ctx.lineTo(this.width === 1 ? 0 : (this.width / 2), this.height === 1 ? 0 : (this.height / 2));
91
+ if (!this.strokeDashArray || this.strokeDashArray && supportsLineDash) {
92
+
93
+ // move from center (of virtual box) to its left/top corner
94
+ // we can't assume x1, y1 is top left and x2, y2 is bottom right
95
+ var xMult = this.x1 <= this.x2 ? -1 : 1;
96
+ var yMult = this.y1 <= this.y2 ? -1 : 1;
97
+
98
+ ctx.moveTo(
99
+ this.width === 1 ? 0 : (xMult * this.width / 2),
100
+ this.height === 1 ? 0 : (yMult * this.height / 2));
101
+
102
+ ctx.lineTo(
103
+ this.width === 1 ? 0 : (xMult * -1 * this.width / 2),
104
+ this.height === 1 ? 0 : (yMult * -1 * this.height / 2));
105
+ }
96
106
 
97
107
  ctx.lineWidth = this.strokeWidth;
98
108
 
@@ -100,18 +110,22 @@
100
110
  // make sure setting "fill" changes color of a line
101
111
  // (by copying fillStyle to strokeStyle, since line is stroked, not filled)
102
112
  var origStrokeStyle = ctx.strokeStyle;
103
- ctx.strokeStyle = ctx.fillStyle;
104
- ctx.stroke();
113
+ ctx.strokeStyle = this.stroke || ctx.fillStyle;
114
+ this._renderStroke(ctx);
105
115
  ctx.strokeStyle = origStrokeStyle;
106
116
  },
107
117
 
108
118
  /**
109
- * Returns complexity of an instance
110
- * @method complexity
111
- * @return {Number} complexity
119
+ * @private
120
+ * @param {CanvasRenderingContext2D} ctx Context to render on
112
121
  */
113
- complexity: function() {
114
- return 1;
122
+ _renderDashedStroke: function(ctx) {
123
+ var x = this.width === 1 ? 0 : -this.width / 2,
124
+ y = this.height === 1 ? 0 : -this.height / 2;
125
+
126
+ ctx.beginPath();
127
+ fabric.util.drawDashedLine(ctx, x, y, -x, -y, this.strokeDashArray);
128
+ ctx.closePath();
115
129
  },
116
130
 
117
131
  /**
@@ -129,35 +143,52 @@
129
143
  });
130
144
  },
131
145
 
146
+ /* _TO_SVG_START_ */
132
147
  /**
133
148
  * Returns SVG representation of an instance
134
- * @method toSVG
135
149
  * @return {String} svg representation of an instance
136
150
  */
137
151
  toSVG: function() {
138
- return [
152
+ var markup = [];
153
+
154
+ if (this.stroke && this.stroke.toLive) {
155
+ markup.push(this.stroke.toSVG(this, true));
156
+ }
157
+
158
+ markup.push(
139
159
  '<line ',
140
- 'x1="', this.get('x1'), '" ',
141
- 'y1="', this.get('y1'), '" ',
142
- 'x2="', this.get('x2'), '" ',
143
- 'y2="', this.get('y2'), '" ',
144
- 'style="', this.getSvgStyles(), '" ',
145
- '/>'
146
- ].join('');
160
+ 'x1="', this.get('x1'),
161
+ '" y1="', this.get('y1'),
162
+ '" x2="', this.get('x2'),
163
+ '" y2="', this.get('y2'),
164
+ '" style="', this.getSvgStyles(),
165
+ '"/>'
166
+ );
167
+
168
+ return markup.join('');
169
+ },
170
+ /* _TO_SVG_END_ */
171
+
172
+ /**
173
+ * Returns complexity of an instance
174
+ * @return {Number} complexity
175
+ */
176
+ complexity: function() {
177
+ return 1;
147
178
  }
148
179
  });
149
180
 
181
+ /* _FROM_SVG_START_ */
150
182
  /**
151
183
  * List of attribute names to account for when parsing SVG element (used by {@link fabric.Line.fromElement})
152
184
  * @static
153
185
  * @see http://www.w3.org/TR/SVG/shapes.html#LineElement
154
186
  */
155
- fabric.Line.ATTRIBUTE_NAMES = 'x1 y1 x2 y2 stroke stroke-width transform'.split(' ');
187
+ fabric.Line.ATTRIBUTE_NAMES = fabric.SHARED_ATTRIBUTES.concat('x1 y1 x2 y2'.split(' '));
156
188
 
157
189
  /**
158
190
  * Returns fabric.Line instance from an SVG element
159
191
  * @static
160
- * @method fabric.Line.fromElement
161
192
  * @param {SVGElement} element Element to parse
162
193
  * @param {Object} [options] Options object
163
194
  * @return {fabric.Line} instance of fabric.Line
@@ -172,11 +203,11 @@
172
203
  ];
173
204
  return new fabric.Line(points, extend(parsedAttributes, options));
174
205
  };
206
+ /* _FROM_SVG_END_ */
175
207
 
176
208
  /**
177
209
  * Returns fabric.Line instance from an object representation
178
210
  * @static
179
- * @method fabric.Line.fromObject
180
211
  * @param {Object} object Object to create an instance from
181
212
  * @return {fabric.Line} instance of fabric.Line
182
213
  */
@@ -185,4 +216,4 @@
185
216
  return new fabric.Line(points, object);
186
217
  };
187
218
 
188
- })(typeof exports !== 'undefined' ? exports : this);
219
+ })(typeof exports !== 'undefined' ? exports : this);