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
@@ -0,0 +1,61 @@
1
+ /**
2
+ * @namespace fabric.Image.filters
3
+ * @memberOf fabric.Image
4
+ */
5
+ fabric.Image.filters = fabric.Image.filters || { };
6
+
7
+ /**
8
+ * Sepia2 filter class
9
+ * @class fabric.Image.filters.Sepia2
10
+ * @memberOf fabric.Image.filters
11
+ */
12
+ fabric.Image.filters.Sepia2 = fabric.util.createClass(/** @lends fabric.Image.filters.Sepia2.prototype */ {
13
+
14
+ /**
15
+ * Filter type
16
+ * @param {String} type
17
+ * @default
18
+ */
19
+ type: 'Sepia2',
20
+
21
+ /**
22
+ * Applies filter to canvas element
23
+ * @memberOf fabric.Image.filters.Sepia.prototype
24
+ * @param {Object} canvasEl Canvas element to apply filter to
25
+ */
26
+ applyTo: function(canvasEl) {
27
+ var context = canvasEl.getContext('2d'),
28
+ imageData = context.getImageData(0, 0, canvasEl.width, canvasEl.height),
29
+ data = imageData.data,
30
+ iLen = data.length, i, r, g, b;
31
+
32
+ for (i = 0; i < iLen; i+=4) {
33
+ r = data[i];
34
+ g = data[i + 1];
35
+ b = data[i + 2];
36
+
37
+ data[i] = (r * 0.393 + g * 0.769 + b * 0.189 ) / 1.351;
38
+ data[i + 1] = (r * 0.349 + g * 0.686 + b * 0.168 ) / 1.203;
39
+ data[i + 2] = (r * 0.272 + g * 0.534 + b * 0.131 ) / 2.140;
40
+ }
41
+
42
+ context.putImageData(imageData, 0, 0);
43
+ },
44
+
45
+ /**
46
+ * Returns json representation of filter
47
+ * @return {String} json representation of filter
48
+ */
49
+ toJSON: function() {
50
+ return { type: this.type };
51
+ }
52
+ });
53
+
54
+ /**
55
+ * Returns filter instance from an object representation
56
+ * @static
57
+ * @return {fabric.Image.filters.Sepia2} Instance of fabric.Image.filters.Sepia2
58
+ */
59
+ fabric.Image.filters.Sepia2.fromObject = function() {
60
+ return new fabric.Image.filters.Sepia2();
61
+ };
@@ -0,0 +1,58 @@
1
+ /**
2
+ * @namespace fabric.Image.filters
3
+ * @memberOf fabric.Image
4
+ */
5
+ fabric.Image.filters = fabric.Image.filters || { };
6
+
7
+ /**
8
+ * Sepia filter class
9
+ * @class fabric.Image.filters.Sepia
10
+ * @memberOf fabric.Image.filters
11
+ */
12
+ fabric.Image.filters.Sepia = fabric.util.createClass(/** @lends fabric.Image.filters.Sepia.prototype */ {
13
+
14
+ /**
15
+ * Filter type
16
+ * @param {String} type
17
+ * @default
18
+ */
19
+ type: 'Sepia',
20
+
21
+ /**
22
+ * Applies filter to canvas element
23
+ * @memberOf fabric.Image.filters.Sepia.prototype
24
+ * @param {Object} canvasEl Canvas element to apply filter to
25
+ */
26
+ applyTo: function(canvasEl) {
27
+ var context = canvasEl.getContext('2d'),
28
+ imageData = context.getImageData(0, 0, canvasEl.width, canvasEl.height),
29
+ data = imageData.data,
30
+ iLen = data.length, i, avg;
31
+
32
+ for (i = 0; i < iLen; i+=4) {
33
+ avg = 0.3 * data[i] + 0.59 * data[i + 1] + 0.11 * data[i + 2];
34
+ data[i] = avg + 100;
35
+ data[i + 1] = avg + 50;
36
+ data[i + 2] = avg + 255;
37
+ }
38
+
39
+ context.putImageData(imageData, 0, 0);
40
+ },
41
+
42
+ /**
43
+ * Returns json representation of filter
44
+ * @return {String} json representation of filter
45
+ */
46
+ toJSON: function() {
47
+ return { type: this.type };
48
+ }
49
+ });
50
+
51
+ /**
52
+ * Returns filter instance from an object representation
53
+ * @static
54
+ * @return {fabric.Image.filters.Sepia} Instance of fabric.Image.filters.Sepia
55
+ */
56
+ fabric.Image.filters.Sepia.fromObject = function() {
57
+ return new fabric.Image.filters.Sepia();
58
+ };
@@ -0,0 +1,80 @@
1
+ /**
2
+ * @namespace fabric.Image.filters
3
+ * @memberOf fabric.Image
4
+ */
5
+ fabric.Image.filters = fabric.Image.filters || { };
6
+
7
+ /**
8
+ * Tint filter class
9
+ * @class fabric.Image.filters.Tint
10
+ * @memberOf fabric.Image.filters
11
+ */
12
+ fabric.Image.filters.Tint = fabric.util.createClass(/** @lends fabric.Image.filters.Tint.prototype */ {
13
+
14
+ /**
15
+ * Filter type
16
+ * @param {String} type
17
+ * @default
18
+ */
19
+ type: 'Tint',
20
+
21
+ /**
22
+ * Constructor
23
+ * @memberOf fabric.Image.filters.Tint.prototype
24
+ * @param {Object} [options] Options object
25
+ */
26
+ initialize: function(options) {
27
+ options = options || { };
28
+ this.color = options.color || 0;
29
+ },
30
+
31
+ /**
32
+ * Applies filter to canvas element
33
+ * @param {Object} canvasEl Canvas element to apply filter to
34
+ */
35
+ applyTo: function(canvasEl) {
36
+ var context = canvasEl.getContext('2d'),
37
+ imageData = context.getImageData(0, 0, canvasEl.width, canvasEl.height),
38
+ data = imageData.data,
39
+ iLen = data.length, i, a;
40
+
41
+ var rgb = parseInt(this.color, 10).toString(16);
42
+
43
+ var cr = parseInt('0x' + rgb.substr(0, 2), 16);
44
+ var cg = parseInt('0x' + rgb.substr(2, 2), 16);
45
+ var cb = parseInt('0x' + rgb.substr(4, 2), 16);
46
+
47
+ for (i = 0; i < iLen; i+=4) {
48
+ a = data[i+3];
49
+
50
+ if (a > 0){
51
+ data[i] = cr;
52
+ data[i+1] = cg;
53
+ data[i+2] = cb;
54
+ }
55
+ }
56
+
57
+ context.putImageData(imageData, 0, 0);
58
+ },
59
+
60
+ /**
61
+ * Returns json representation of filter
62
+ * @return {Object} json representation of filter
63
+ */
64
+ toJSON: function() {
65
+ return {
66
+ type: this.type,
67
+ color: this.color
68
+ };
69
+ }
70
+ });
71
+
72
+ /**
73
+ * Returns filter instance from an object representation
74
+ * @static
75
+ * @param {Object} object Object to create an instance from
76
+ * @return {fabric.Image.filters.Tint} Instance of fabric.Image.filters.Tint
77
+ */
78
+ fabric.Image.filters.Tint.fromObject = function(object) {
79
+ return new fabric.Image.filters.Tint(object);
80
+ };
@@ -1,7 +1,13 @@
1
1
  (function() {
2
2
 
3
- function getColorStopFromStyle(el) {
4
- var style = el.getAttribute('style');
3
+ /* _FROM_SVG_START_ */
4
+ function getColorStop(el) {
5
+ var style = el.getAttribute('style'),
6
+ offset = el.getAttribute('offset'),
7
+ color, opacity;
8
+
9
+ // convert percents to absolute values
10
+ offset = parseFloat(offset) / (/%$/.test(offset) ? 100 : 1);
5
11
 
6
12
  if (style) {
7
13
  var keyValuePairs = style.split(/\s*;\s*/);
@@ -17,65 +23,190 @@
17
23
  value = split[1].trim();
18
24
 
19
25
  if (key === 'stop-color') {
20
- return value;
26
+ color = value;
27
+ }
28
+ else if (key === 'stop-opacity') {
29
+ opacity = value;
21
30
  }
22
31
  }
23
32
  }
33
+
34
+ if (!color) {
35
+ color = el.getAttribute('stop-color') || 'rgb(0,0,0)';
36
+ }
37
+ if (!opacity) {
38
+ opacity = el.getAttribute('stop-opacity');
39
+ }
40
+
41
+ // convert rgba color to rgb color - alpha value has no affect in svg
42
+ color = new fabric.Color(color).toRgb();
43
+
44
+ return {
45
+ offset: offset,
46
+ color: color,
47
+ opacity: isNaN(parseFloat(opacity)) ? 1 : parseFloat(opacity)
48
+ };
24
49
  }
50
+ /* _FROM_SVG_END_ */
25
51
 
26
52
  /**
27
53
  * Gradient class
28
- * @class Gradient
29
- * @memberOf fabric
54
+ * @class fabric.Gradient
30
55
  */
31
- fabric.Gradient = fabric.util.createClass(/** @scope fabric.Gradient.prototype */ {
56
+ fabric.Gradient = fabric.util.createClass(/** @lends fabric.Gradient.prototype */ {
32
57
 
33
58
  /**
34
59
  * Constructor
35
- * @method initialize
36
- * @param [options] Options object with x1, y1, x2, y2 and colorStops
60
+ * @param {Object} [options] Options object with type, coords, gradientUnits and colorStops
37
61
  * @return {fabric.Gradient} thisArg
38
62
  */
39
63
  initialize: function(options) {
40
-
41
64
  options || (options = { });
42
65
 
43
- this.x1 = options.x1 || 0;
44
- this.y1 = options.y1 || 0;
45
- this.x2 = options.x2 || 0;
46
- this.y2 = options.y2 || 0;
66
+ var coords = { };
67
+
68
+ this.id = fabric.Object.__uid++;
69
+ this.type = options.type || 'linear';
47
70
 
48
- this.colorStops = options.colorStops;
71
+ coords = {
72
+ x1: options.coords.x1 || 0,
73
+ y1: options.coords.y1 || 0,
74
+ x2: options.coords.x2 || 0,
75
+ y2: options.coords.y2 || 0
76
+ };
77
+
78
+ if (this.type === 'radial') {
79
+ coords.r1 = options.coords.r1 || 0;
80
+ coords.r2 = options.coords.r2 || 0;
81
+ }
82
+
83
+ this.coords = coords;
84
+ this.gradientUnits = options.gradientUnits || 'objectBoundingBox';
85
+ this.colorStops = options.colorStops.slice();
86
+ },
87
+
88
+ /**
89
+ * Adds another colorStop
90
+ * @param {Object} colorStop Object with offset and color
91
+ * @return {fabric.Gradient} thisArg
92
+ */
93
+ addColorStop: function(colorStop) {
94
+ for (var position in colorStop) {
95
+ var color = new fabric.Color(colorStop[position]);
96
+ this.colorStops.push({offset: position, color: color.toRgb(), opacity: color.getAlpha()});
97
+ }
98
+ return this;
49
99
  },
50
100
 
51
101
  /**
52
102
  * Returns object representation of a gradient
53
- * @method toObject
54
103
  * @return {Object}
55
104
  */
56
105
  toObject: function() {
57
106
  return {
58
- x1: this.x1,
59
- x2: this.x2,
60
- y1: this.y1,
61
- y2: this.y2,
107
+ type: this.type,
108
+ coords: this.coords,
109
+ gradientUnits: this.gradientUnits,
62
110
  colorStops: this.colorStops
63
111
  };
64
112
  },
65
113
 
114
+ /* _TO_SVG_START_ */
115
+ /**
116
+ * Returns SVG representation of an gradient
117
+ * @param {Object} object Object to create a gradient for
118
+ * @param {Boolean} normalize Whether coords should be normalized
119
+ * @return {String} SVG representation of an gradient (linear/radial)
120
+ */
121
+ toSVG: function(object, normalize) {
122
+ var coords = fabric.util.object.clone(this.coords),
123
+ markup;
124
+
125
+ // colorStops must be sorted ascending
126
+ this.colorStops.sort(function(a, b) {
127
+ return a.offset - b.offset;
128
+ });
129
+
130
+ if (normalize && this.gradientUnits === 'userSpaceOnUse') {
131
+ coords.x1 += object.width / 2;
132
+ coords.y1 += object.height / 2;
133
+ coords.x2 += object.width / 2;
134
+ coords.y2 += object.height / 2;
135
+ }
136
+ else if (this.gradientUnits === 'objectBoundingBox') {
137
+ _convertValuesToPercentUnits(object, coords);
138
+ }
139
+
140
+ if (this.type === 'linear') {
141
+ markup = [
142
+ '<linearGradient ',
143
+ 'id="SVGID_', this.id,
144
+ '" gradientUnits="', this.gradientUnits,
145
+ '" x1="', coords.x1,
146
+ '" y1="', coords.y1,
147
+ '" x2="', coords.x2,
148
+ '" y2="', coords.y2,
149
+ '">'
150
+ ];
151
+ }
152
+ else if (this.type === 'radial') {
153
+ markup = [
154
+ '<radialGradient ',
155
+ 'id="SVGID_', this.id,
156
+ '" gradientUnits="', this.gradientUnits,
157
+ '" cx="', coords.x2,
158
+ '" cy="', coords.y2,
159
+ '" r="', coords.r2,
160
+ '" fx="', coords.x1,
161
+ '" fy="', coords.y1,
162
+ '">'
163
+ ];
164
+ }
165
+
166
+ for (var i = 0; i < this.colorStops.length; i++) {
167
+ markup.push(
168
+ '<stop ',
169
+ 'offset="', (this.colorStops[i].offset * 100) + '%',
170
+ '" style="stop-color:', this.colorStops[i].color,
171
+ (this.colorStops[i].opacity ? ';stop-opacity: ' + this.colorStops[i].opacity : ';'),
172
+ '"/>'
173
+ );
174
+ }
175
+
176
+ markup.push((this.type === 'linear' ? '</linearGradient>' : '</radialGradient>'));
177
+
178
+ return markup.join('');
179
+ },
180
+ /* _TO_SVG_END_ */
181
+
66
182
  /**
67
183
  * Returns an instance of CanvasGradient
68
- * @method toLive
69
184
  * @param ctx
70
185
  * @return {CanvasGradient}
71
186
  */
72
187
  toLive: function(ctx) {
73
- var gradient = ctx.createLinearGradient(
74
- this.x1, this.y1, this.x2 || ctx.canvas.width, this.y2);
188
+ var gradient;
189
+
190
+ if (!this.type) return;
191
+
192
+ if (this.type === 'linear') {
193
+ gradient = ctx.createLinearGradient(
194
+ this.coords.x1, this.coords.y1, this.coords.x2, this.coords.y2);
195
+ }
196
+ else if (this.type === 'radial') {
197
+ gradient = ctx.createRadialGradient(
198
+ this.coords.x1, this.coords.y1, this.coords.r1, this.coords.x2, this.coords.y2, this.coords.r2);
199
+ }
75
200
 
76
- for (var position in this.colorStops) {
77
- var colorValue = this.colorStops[position];
78
- gradient.addColorStop(parseFloat(position), colorValue);
201
+ for (var i = 0, len = this.colorStops.length; i < len; i++) {
202
+ var color = this.colorStops[i].color,
203
+ opacity = this.colorStops[i].opacity,
204
+ offset = this.colorStops[i].offset;
205
+
206
+ if (typeof opacity !== 'undefined') {
207
+ color = new fabric.Color(color).setAlpha(opacity).toRgba();
208
+ }
209
+ gradient.addColorStop(parseFloat(offset), color);
79
210
  }
80
211
 
81
212
  return gradient;
@@ -84,68 +215,94 @@
84
215
 
85
216
  fabric.util.object.extend(fabric.Gradient, {
86
217
 
218
+ /* _FROM_SVG_START_ */
87
219
  /**
88
220
  * Returns {@link fabric.Gradient} instance from an SVG element
89
- * @method fromElement
90
221
  * @static
91
222
  * @memberof fabric.Gradient
92
223
  * @see http://www.w3.org/TR/SVG/pservers.html#LinearGradientElement
224
+ * @see http://www.w3.org/TR/SVG/pservers.html#RadialGradientElement
93
225
  */
94
226
  fromElement: function(el, instance) {
95
227
 
96
228
  /**
97
229
  * @example:
98
230
  *
99
- * <linearGradient id="grad1">
231
+ * <linearGradient id="linearGrad1">
100
232
  * <stop offset="0%" stop-color="white"/>
101
233
  * <stop offset="100%" stop-color="black"/>
102
234
  * </linearGradient>
103
235
  *
104
236
  * OR
105
237
  *
106
- * <linearGradient id="grad1">
107
- * <stop offset="0%" style="stop-color:rgb(255,255,255)"/>
108
- * <stop offset="100%" style="stop-color:rgb(0,0,0)"/>
238
+ * <linearGradient id="linearGrad2">
239
+ * <stop offset="0" style="stop-color:rgb(255,255,255)"/>
240
+ * <stop offset="1" style="stop-color:rgb(0,0,0)"/>
109
241
  * </linearGradient>
110
242
  *
243
+ * OR
244
+ *
245
+ * <radialGradient id="radialGrad1">
246
+ * <stop offset="0%" stop-color="white" stop-opacity="1" />
247
+ * <stop offset="50%" stop-color="black" stop-opacity="0.5" />
248
+ * <stop offset="100%" stop-color="white" stop-opacity="1" />
249
+ * </radialGradient>
250
+ *
251
+ * OR
252
+ *
253
+ * <radialGradient id="radialGrad2">
254
+ * <stop offset="0" stop-color="rgb(255,255,255)" />
255
+ * <stop offset="0.5" stop-color="rgb(0,0,0)" />
256
+ * <stop offset="1" stop-color="rgb(255,255,255)" />
257
+ * </radialGradient>
258
+ *
111
259
  */
112
260
 
113
261
  var colorStopEls = el.getElementsByTagName('stop'),
114
- offset,
115
- colorStops = { },
116
- coords = {
117
- x1: el.getAttribute('x1') || 0,
118
- y1: el.getAttribute('y1') || 0,
119
- x2: el.getAttribute('x2') || '100%',
120
- y2: el.getAttribute('y2') || 0
121
- };
262
+ type = (el.nodeName === 'linearGradient' ? 'linear' : 'radial'),
263
+ gradientUnits = el.getAttribute('gradientUnits') || 'objectBoundingBox',
264
+ colorStops = [],
265
+ coords = { };
122
266
 
123
- for (var i = colorStopEls.length; i--; ) {
124
- el = colorStopEls[i];
125
- offset = el.getAttribute('offset');
267
+ if (type === 'linear') {
268
+ coords = {
269
+ x1: el.getAttribute('x1') || 0,
270
+ y1: el.getAttribute('y1') || 0,
271
+ x2: el.getAttribute('x2') || '100%',
272
+ y2: el.getAttribute('y2') || 0
273
+ };
274
+ }
275
+ else if (type === 'radial') {
276
+ coords = {
277
+ x1: el.getAttribute('fx') || el.getAttribute('cx') || '50%',
278
+ y1: el.getAttribute('fy') || el.getAttribute('cy') || '50%',
279
+ r1: 0,
280
+ x2: el.getAttribute('cx') || '50%',
281
+ y2: el.getAttribute('cy') || '50%',
282
+ r2: el.getAttribute('r') || '50%'
283
+ };
284
+ }
126
285
 
127
- // convert percents to absolute values
128
- offset = parseFloat(offset) / (/%$/.test(offset) ? 100 : 1);
129
- colorStops[offset] = getColorStopFromStyle(el) || el.getAttribute('stop-color');
286
+ for (var i = colorStopEls.length; i--; ) {
287
+ colorStops.push(getColorStop(colorStopEls[i]));
130
288
  }
131
289
 
132
290
  _convertPercentUnitsToValues(instance, coords);
133
291
 
134
292
  return new fabric.Gradient({
135
- x1: coords.x1,
136
- y1: coords.y1,
137
- x2: coords.x2,
138
- y2: coords.y2,
293
+ type: type,
294
+ coords: coords,
295
+ gradientUnits: gradientUnits,
139
296
  colorStops: colorStops
140
297
  });
141
298
  },
299
+ /* _FROM_SVG_END_ */
142
300
 
143
301
  /**
144
302
  * Returns {@link fabric.Gradient} instance from its object representation
145
- * @method forObject
146
303
  * @static
147
- * @param obj
148
- * @param [options]
304
+ * @param {Object} obj
305
+ * @param {Object} [options] Options object
149
306
  * @memberof fabric.Gradient
150
307
  */
151
308
  forObject: function(obj, options) {
@@ -155,11 +312,14 @@
155
312
  }
156
313
  });
157
314
 
315
+ /**
316
+ * @private
317
+ */
158
318
  function _convertPercentUnitsToValues(object, options) {
159
319
  for (var prop in options) {
160
320
  if (typeof options[prop] === 'string' && /^\d+%$/.test(options[prop])) {
161
321
  var percents = parseFloat(options[prop], 10);
162
- if (prop === 'x1' || prop === 'x2') {
322
+ if (prop === 'x1' || prop === 'x2' || prop === 'r2') {
163
323
  options[prop] = fabric.util.toFixed(object.width * percents / 100, 2);
164
324
  }
165
325
  else if (prop === 'y1' || prop === 'y2') {
@@ -176,36 +336,28 @@
176
336
  }
177
337
  }
178
338
 
339
+ /* _TO_SVG_START_ */
179
340
  /**
180
- * Parses an SVG document, returning all of the gradient declarations found in it
181
- * @static
182
- * @function
183
- * @memberOf fabric
184
- * @method getGradientDefs
185
- * @param {SVGDocument} doc SVG document to parse
186
- * @return {Object} Gradient definitions; key corresponds to element id, value -- to gradient definition element
341
+ * @private
187
342
  */
188
- function getGradientDefs(doc) {
189
- var linearGradientEls = doc.getElementsByTagName('linearGradient'),
190
- radialGradientEls = doc.getElementsByTagName('radialGradient'),
191
- el, i,
192
- gradientDefs = { };
193
-
194
- i = linearGradientEls.length;
195
- for (; i--; ) {
196
- el = linearGradientEls[i];
197
- gradientDefs[el.getAttribute('id')] = el;
198
- }
199
-
200
- i = radialGradientEls.length;
201
- for (; i--; ) {
202
- el = radialGradientEls[i];
203
- gradientDefs[el.getAttribute('id')] = el;
343
+ function _convertValuesToPercentUnits(object, options) {
344
+ for (var prop in options) {
345
+ // normalize rendering point (should be from center rather than top/left corner of the shape)
346
+ if (prop === 'x1' || prop === 'x2') {
347
+ options[prop] += fabric.util.toFixed(object.width / 2, 2);
348
+ }
349
+ else if (prop === 'y1' || prop === 'y2') {
350
+ options[prop] += fabric.util.toFixed(object.height / 2, 2);
351
+ }
352
+ // convert to percent units
353
+ if (prop === 'x1' || prop === 'x2' || prop === 'r2') {
354
+ options[prop] = fabric.util.toFixed(options[prop] / object.width * 100, 2) + '%';
355
+ }
356
+ else if (prop === 'y1' || prop === 'y2') {
357
+ options[prop] = fabric.util.toFixed(options[prop] / object.height * 100, 2) + '%';
358
+ }
204
359
  }
205
-
206
- return gradientDefs;
207
360
  }
361
+ /* _TO_SVG_END_ */
208
362
 
209
- fabric.getGradientDefs = getGradientDefs;
210
-
211
- })();
363
+ })();