fabric-rails 0.0.7 → 0.0.8
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/CHANGELOG.md +4 -0
- data/README.md +1 -1
- data/lib/fabric/rails/version.rb +2 -2
- data/vendor/assets/javascripts/fabric.js +139 -100
- metadata +6 -6
data/CHANGELOG.md
CHANGED
data/README.md
CHANGED
data/lib/fabric/rails/version.rb
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
/* build: `node build.js modules=ALL` */
|
2
2
|
/*! Fabric.js Copyright 2008-2012, Printio (Juriy Zaytsev, Maxim Chernyak) */
|
3
3
|
|
4
|
-
var fabric = fabric || { version: "0.9.
|
4
|
+
var fabric = fabric || { version: "0.9.8" };
|
5
5
|
|
6
6
|
if (typeof exports != 'undefined') {
|
7
7
|
exports.fabric = fabric;
|
@@ -8016,20 +8016,9 @@ fabric.util.object.extend(fabric.StaticCanvas.prototype, {
|
|
8016
8016
|
: this.fill;
|
8017
8017
|
}
|
8018
8018
|
|
8019
|
-
if (
|
8020
|
-
|
8021
|
-
|
8022
|
-
-this.group.width / 2,
|
8023
|
-
-this.group.height / 2
|
8024
|
-
);
|
8025
|
-
ctx.transform(m[0], m[1], m[2], m[3], m[4], m[5]);
|
8026
|
-
}
|
8027
|
-
else {
|
8028
|
-
ctx.translate(
|
8029
|
-
-this.group.width / 2 + this.width / 2,
|
8030
|
-
-this.group.height / 2 + this.height / 2
|
8031
|
-
);
|
8032
|
-
}
|
8019
|
+
if (m && this.group) {
|
8020
|
+
ctx.translate(-this.group.width/2, -this.group.height/2);
|
8021
|
+
ctx.transform(m[0], m[1], m[2], m[3], m[4], m[5]);
|
8033
8022
|
}
|
8034
8023
|
|
8035
8024
|
this._render(ctx, noTransform);
|
@@ -8135,10 +8124,11 @@ fabric.util.object.extend(fabric.StaticCanvas.prototype, {
|
|
8135
8124
|
*/
|
8136
8125
|
setCoords: function() {
|
8137
8126
|
|
8138
|
-
var strokeWidth = this.strokeWidth > 1 ? this.strokeWidth : 0
|
8127
|
+
var strokeWidth = this.strokeWidth > 1 ? this.strokeWidth : 0,
|
8128
|
+
padding = this.padding;
|
8139
8129
|
|
8140
|
-
this.currentWidth = (this.width + strokeWidth) * this.scaleX;
|
8141
|
-
this.currentHeight = (this.height + strokeWidth) * this.scaleY;
|
8130
|
+
this.currentWidth = (this.width + strokeWidth) * this.scaleX + padding * 2;
|
8131
|
+
this.currentHeight = (this.height + strokeWidth) * this.scaleY + padding * 2;
|
8142
8132
|
|
8143
8133
|
this._hypotenuse = Math.sqrt(
|
8144
8134
|
Math.pow(this.currentWidth / 2, 2) +
|
@@ -8249,8 +8239,9 @@ fabric.util.object.extend(fabric.StaticCanvas.prototype, {
|
|
8249
8239
|
drawBorders: function(ctx) {
|
8250
8240
|
if (!this.hasBorders) return;
|
8251
8241
|
|
8252
|
-
var
|
8253
|
-
|
8242
|
+
var MIN_SCALE_LIMIT = fabric.Object.MIN_SCALE_LIMIT,
|
8243
|
+
padding = this.padding,
|
8244
|
+
padding2 = padding * 2,
|
8254
8245
|
strokeWidth = this.strokeWidth > 1 ? this.strokeWidth : 0;
|
8255
8246
|
|
8256
8247
|
ctx.save();
|
@@ -8269,14 +8260,20 @@ fabric.util.object.extend(fabric.StaticCanvas.prototype, {
|
|
8269
8260
|
h = this.getHeight();
|
8270
8261
|
|
8271
8262
|
ctx.strokeRect(
|
8272
|
-
~~(-(w / 2) -
|
8273
|
-
~~(-(h / 2) -
|
8263
|
+
~~(-(w / 2) - padding - strokeWidth / 2 * this.scaleX) + 0.5, // offset needed to make lines look sharper
|
8264
|
+
~~(-(h / 2) - padding - strokeWidth / 2 * this.scaleY) + 0.5,
|
8274
8265
|
~~(w + padding2 + strokeWidth * this.scaleX),
|
8275
8266
|
~~(h + padding2 + strokeWidth * this.scaleY)
|
8276
8267
|
);
|
8277
8268
|
|
8278
8269
|
if (this.hasRotatingPoint && !this.hideCorners && !this.lockRotation) {
|
8279
|
-
|
8270
|
+
|
8271
|
+
var rotateHeight = (
|
8272
|
+
this.flipY
|
8273
|
+
? h + (strokeWidth * this.scaleY) + (padding * 2)
|
8274
|
+
: -h - (strokeWidth * this.scaleY) - (padding * 2)
|
8275
|
+
) / 2;
|
8276
|
+
|
8280
8277
|
var rotateWidth = (-w/2);
|
8281
8278
|
|
8282
8279
|
ctx.beginPath();
|
@@ -8362,82 +8359,97 @@ fabric.util.object.extend(fabric.StaticCanvas.prototype, {
|
|
8362
8359
|
var size = this.cornersize,
|
8363
8360
|
size2 = size / 2,
|
8364
8361
|
strokeWidth2 = this.strokeWidth / 2,
|
8365
|
-
padding = this.padding,
|
8366
8362
|
left = -(this.width / 2),
|
8367
8363
|
top = -(this.height / 2),
|
8368
8364
|
_left,
|
8369
8365
|
_top,
|
8370
8366
|
sizeX = size / this.scaleX,
|
8371
8367
|
sizeY = size / this.scaleY,
|
8372
|
-
|
8373
|
-
|
8374
|
-
|
8375
|
-
|
8376
|
-
|
8368
|
+
paddingX = this.padding / this.scaleX,
|
8369
|
+
paddingY = this.padding / this.scaleY,
|
8370
|
+
scaleOffsetY = size2 / this.scaleY,
|
8371
|
+
scaleOffsetX = size2 / this.scaleX,
|
8372
|
+
scaleOffsetSizeX = (size2 - size) / this.scaleX,
|
8373
|
+
scaleOffsetSizeY = (size2 - size) / this.scaleY,
|
8374
|
+
height = this.height,
|
8375
|
+
width = this.width;
|
8377
8376
|
|
8378
8377
|
ctx.save();
|
8379
8378
|
|
8379
|
+
ctx.lineWidth = 1 / Math.max(this.scaleX, this.scaleY);
|
8380
|
+
|
8380
8381
|
ctx.globalAlpha = this.isMoving ? this.borderOpacityWhenMoving : 1;
|
8381
|
-
ctx.fillStyle = this.cornerColor;
|
8382
|
+
ctx.strokeStyle = ctx.fillStyle = this.cornerColor;
|
8382
8383
|
|
8383
8384
|
// top-left
|
8384
|
-
_left = left - scaleOffsetX - strokeWidth2;
|
8385
|
-
_top = top - scaleOffsetY - strokeWidth2;
|
8386
|
-
|
8385
|
+
_left = left - scaleOffsetX - strokeWidth2 - paddingX;
|
8386
|
+
_top = top - scaleOffsetY - strokeWidth2 - paddingY;
|
8387
|
+
|
8388
|
+
ctx.clearRect(_left, _top, sizeX, sizeY);
|
8389
|
+
ctx.strokeRect(_left, _top, sizeX, sizeY);
|
8387
8390
|
|
8388
8391
|
// top-right
|
8389
|
-
_left = left +
|
8390
|
-
_top = top - scaleOffsetY - strokeWidth2;
|
8391
|
-
|
8392
|
+
_left = left + width - scaleOffsetX + strokeWidth2 + paddingX;
|
8393
|
+
_top = top - scaleOffsetY - strokeWidth2 - paddingY;
|
8394
|
+
|
8395
|
+
ctx.clearRect(_left, _top, sizeX, sizeY);
|
8396
|
+
ctx.strokeRect(_left, _top, sizeX, sizeY);
|
8392
8397
|
|
8393
8398
|
// bottom-left
|
8394
|
-
_left = left - scaleOffsetX - strokeWidth2;
|
8395
|
-
_top = top + height + scaleOffsetSizeY + strokeWidth2;
|
8396
|
-
|
8399
|
+
_left = left - scaleOffsetX - strokeWidth2 - paddingX;
|
8400
|
+
_top = top + height + scaleOffsetSizeY + strokeWidth2 + paddingY;
|
8401
|
+
|
8402
|
+
ctx.clearRect(_left, _top, sizeX, sizeY);
|
8403
|
+
ctx.strokeRect(_left, _top, sizeX, sizeY);
|
8397
8404
|
|
8398
8405
|
// bottom-right
|
8399
|
-
_left = left +
|
8400
|
-
_top = top + height + scaleOffsetSizeY + strokeWidth2;
|
8401
|
-
|
8402
|
-
|
8403
|
-
|
8404
|
-
|
8405
|
-
|
8406
|
-
|
8407
|
-
|
8408
|
-
|
8409
|
-
|
8410
|
-
|
8411
|
-
|
8412
|
-
|
8413
|
-
|
8414
|
-
|
8415
|
-
|
8416
|
-
|
8417
|
-
|
8418
|
-
|
8419
|
-
|
8420
|
-
|
8421
|
-
|
8406
|
+
_left = left + width + scaleOffsetSizeX + strokeWidth2 + paddingX;
|
8407
|
+
_top = top + height + scaleOffsetSizeY + strokeWidth2 + paddingY;
|
8408
|
+
|
8409
|
+
ctx.clearRect(_left, _top, sizeX, sizeY);
|
8410
|
+
ctx.strokeRect(_left, _top, sizeX, sizeY);
|
8411
|
+
|
8412
|
+
if (!this.lockUniScaling) {
|
8413
|
+
// middle-top
|
8414
|
+
_left = left + width/2 - scaleOffsetX;
|
8415
|
+
_top = top - scaleOffsetY - strokeWidth2 - paddingY;
|
8416
|
+
|
8417
|
+
ctx.clearRect(_left, _top, sizeX, sizeY);
|
8418
|
+
ctx.strokeRect(_left, _top, sizeX, sizeY);
|
8419
|
+
|
8420
|
+
// middle-bottom
|
8421
|
+
_left = left + width/2 - scaleOffsetX;
|
8422
|
+
_top = top + height + scaleOffsetSizeY + strokeWidth2 + paddingY;
|
8423
|
+
|
8424
|
+
ctx.clearRect(_left, _top, sizeX, sizeY);
|
8425
|
+
ctx.strokeRect(_left, _top, sizeX, sizeY);
|
8426
|
+
|
8427
|
+
// middle-right
|
8428
|
+
_left = left + width + scaleOffsetSizeX + strokeWidth2 + paddingX;
|
8429
|
+
_top = top + height/2 - scaleOffsetY;
|
8430
|
+
|
8431
|
+
ctx.clearRect(_left, _top, sizeX, sizeY);
|
8432
|
+
ctx.strokeRect(_left, _top, sizeX, sizeY);
|
8433
|
+
|
8434
|
+
// middle-left
|
8435
|
+
_left = left - scaleOffsetX - strokeWidth2 - paddingX;
|
8436
|
+
_top = top + height/2 - scaleOffsetY;
|
8437
|
+
|
8438
|
+
ctx.clearRect(_left, _top, sizeX, sizeY);
|
8439
|
+
ctx.strokeRect(_left, _top, sizeX, sizeY);
|
8440
|
+
}
|
8422
8441
|
|
8423
8442
|
// middle-top-rotate
|
8424
8443
|
if (this.hasRotatingPoint) {
|
8425
|
-
// _left = left + this.width/2;
|
8426
|
-
// _top = top - (45 / this.scaleY) + scaleOffsetY;
|
8427
|
-
|
8428
|
-
// ctx.save();
|
8429
|
-
// ctx.beginPath();
|
8430
|
-
// ctx.arc(_left, _top, sizeX / 2, 0, Math.PI * 2, false);
|
8431
|
-
// ctx.fill();
|
8432
|
-
// ctx.restore();
|
8433
8444
|
|
8434
|
-
_left = left +
|
8445
|
+
_left = left + width/2 - scaleOffsetX;
|
8435
8446
|
|
8436
8447
|
_top = this.flipY ?
|
8437
|
-
(top + height + (this.rotatingPointOffset / this.scaleY) - sizeY/2 + strokeWidth2)
|
8438
|
-
: (top - (this.rotatingPointOffset / this.scaleY) - sizeY/2 - strokeWidth2);
|
8448
|
+
(top + height + (this.rotatingPointOffset / this.scaleY) - sizeY/2 + strokeWidth2 + paddingY)
|
8449
|
+
: (top - (this.rotatingPointOffset / this.scaleY) - sizeY/2 - strokeWidth2 - paddingY);
|
8439
8450
|
|
8440
|
-
ctx.
|
8451
|
+
ctx.clearRect(_left, _top, sizeX, sizeY);
|
8452
|
+
ctx.strokeRect(_left, _top, sizeX, sizeY);
|
8441
8453
|
}
|
8442
8454
|
|
8443
8455
|
ctx.restore();
|
@@ -8675,6 +8687,9 @@ fabric.util.object.extend(fabric.StaticCanvas.prototype, {
|
|
8675
8687
|
if (i === 'mtr' && !this.hasRotatingPoint) {
|
8676
8688
|
return false;
|
8677
8689
|
}
|
8690
|
+
if (this.lockUniScaling && (i === 'mt' || i === 'mr' || i === 'mb' || i === 'ml')) {
|
8691
|
+
return false;
|
8692
|
+
}
|
8678
8693
|
|
8679
8694
|
lines = this._getImageLines(this.oCoords[i].corner, i);
|
8680
8695
|
// debugging
|
@@ -9248,6 +9263,10 @@ fabric.util.object.extend(fabric.StaticCanvas.prototype, {
|
|
9248
9263
|
_render: function(ctx) {
|
9249
9264
|
ctx.beginPath();
|
9250
9265
|
|
9266
|
+
if (this.group) {
|
9267
|
+
ctx.translate(-this.group.width/2 + this.left, -this.group.height / 2 + this.top);
|
9268
|
+
}
|
9269
|
+
|
9251
9270
|
// move from center (of virtual box) to its left/top corner
|
9252
9271
|
ctx.moveTo(this.width === 1 ? 0 : (-this.width / 2), this.height === 1 ? 0 : (-this.height / 2));
|
9253
9272
|
ctx.lineTo(this.width === 1 ? 0 : (this.width / 2), this.height === 1 ? 0 : (this.height / 2));
|
@@ -9714,6 +9733,9 @@ fabric.util.object.extend(fabric.StaticCanvas.prototype, {
|
|
9714
9733
|
ctx.beginPath();
|
9715
9734
|
ctx.save();
|
9716
9735
|
ctx.globalAlpha *= this.opacity;
|
9736
|
+
if (this.transformMatrix && this.group) {
|
9737
|
+
ctx.translate(this.cx, this.cy);
|
9738
|
+
}
|
9717
9739
|
ctx.transform(1, 0, 0, this.ry/this.rx, 0, 0);
|
9718
9740
|
ctx.arc(noTransform ? this.left : 0, noTransform ? this.top : 0, this.rx, 0, piBy2, false);
|
9719
9741
|
if (this.stroke) {
|
@@ -9752,14 +9774,24 @@ fabric.util.object.extend(fabric.StaticCanvas.prototype, {
|
|
9752
9774
|
*/
|
9753
9775
|
fabric.Ellipse.fromElement = function(element, options) {
|
9754
9776
|
options || (options = { });
|
9777
|
+
|
9755
9778
|
var parsedAttributes = fabric.parseAttributes(element, fabric.Ellipse.ATTRIBUTE_NAMES);
|
9779
|
+
var cx = parsedAttributes.left;
|
9780
|
+
var cy = parsedAttributes.top;
|
9781
|
+
|
9756
9782
|
if ('left' in parsedAttributes) {
|
9757
9783
|
parsedAttributes.left -= (options.width / 2) || 0;
|
9758
9784
|
}
|
9759
9785
|
if ('top' in parsedAttributes) {
|
9760
9786
|
parsedAttributes.top -= (options.height / 2) || 0;
|
9761
9787
|
}
|
9762
|
-
|
9788
|
+
|
9789
|
+
var ellipse = new fabric.Ellipse(extend(parsedAttributes, options));
|
9790
|
+
|
9791
|
+
ellipse.cx = cx || 0;
|
9792
|
+
ellipse.cy = cy || 0;
|
9793
|
+
|
9794
|
+
return ellipse;
|
9763
9795
|
};
|
9764
9796
|
|
9765
9797
|
/**
|
@@ -9860,8 +9892,15 @@ fabric.util.object.extend(fabric.StaticCanvas.prototype, {
|
|
9860
9892
|
ctx.beginPath();
|
9861
9893
|
ctx.globalAlpha *= this.opacity;
|
9862
9894
|
|
9863
|
-
if (this.group) {
|
9864
|
-
ctx.translate(
|
9895
|
+
if (this.transformMatrix && this.group) {
|
9896
|
+
ctx.translate(
|
9897
|
+
this.width / 2 + this.x,
|
9898
|
+
this.height / 2 + this.y);
|
9899
|
+
}
|
9900
|
+
if (!this.transformMatrix && this.group) {
|
9901
|
+
ctx.translate(
|
9902
|
+
-this.group.width / 2 + this.width / 2 + this.x,
|
9903
|
+
-this.group.height / 2 + this.height / 2 + this.y);
|
9865
9904
|
}
|
9866
9905
|
|
9867
9906
|
ctx.moveTo(x+rx, y);
|
@@ -11101,6 +11140,12 @@ fabric.util.object.extend(fabric.StaticCanvas.prototype, {
|
|
11101
11140
|
*/
|
11102
11141
|
type: 'path-group',
|
11103
11142
|
|
11143
|
+
/**
|
11144
|
+
* @property
|
11145
|
+
* @type String
|
11146
|
+
*/
|
11147
|
+
fill: '',
|
11148
|
+
|
11104
11149
|
/**
|
11105
11150
|
* @property
|
11106
11151
|
* @type Boolean
|
@@ -11157,24 +11202,21 @@ fabric.util.object.extend(fabric.StaticCanvas.prototype, {
|
|
11157
11202
|
|
11158
11203
|
/**
|
11159
11204
|
* Sets certain property to a certain value
|
11160
|
-
* @method
|
11205
|
+
* @method _set
|
11161
11206
|
* @param {String} prop
|
11162
11207
|
* @param {Any} value
|
11163
11208
|
* @return {fabric.PathGroup} thisArg
|
11164
11209
|
*/
|
11165
|
-
|
11166
|
-
|
11167
|
-
|
11210
|
+
_set: function(prop, value) {
|
11211
|
+
|
11212
|
+
if ((prop === 'fill' || prop === 'overlayFill') && value && this.isSameColor()) {
|
11168
11213
|
var i = this.paths.length;
|
11169
11214
|
while (i--) {
|
11170
|
-
this.paths[i].
|
11215
|
+
this.paths[i]._set(prop, value);
|
11171
11216
|
}
|
11172
11217
|
}
|
11173
|
-
|
11174
|
-
|
11175
|
-
parentSet.call(this, prop, value);
|
11176
|
-
}
|
11177
|
-
return this;
|
11218
|
+
|
11219
|
+
return this.callSuper('_set', prop, value);
|
11178
11220
|
},
|
11179
11221
|
|
11180
11222
|
/**
|
@@ -11928,6 +11970,9 @@ fabric.util.object.extend(fabric.StaticCanvas.prototype, {
|
|
11928
11970
|
ctx.save();
|
11929
11971
|
var m = this.transformMatrix;
|
11930
11972
|
this._resetWidthHeight();
|
11973
|
+
if (this.group) {
|
11974
|
+
ctx.translate(-this.group.width/2 + this.width/2, -this.group.height/2 + this.height/2);
|
11975
|
+
}
|
11931
11976
|
if (m) {
|
11932
11977
|
ctx.transform(m[0], m[1], m[2], m[3], m[4], m[5]);
|
11933
11978
|
}
|
@@ -12973,7 +13018,7 @@ fabric.Image.filters.Tint.fromObject = function(object) {
|
|
12973
13018
|
this._initStateProperties();
|
12974
13019
|
this.text = text;
|
12975
13020
|
this.setOptions(options || { });
|
12976
|
-
this.
|
13021
|
+
this._theta = this.angle * Math.PI / 180;
|
12977
13022
|
this._initDimensions();
|
12978
13023
|
this.setCoords();
|
12979
13024
|
},
|
@@ -13555,6 +13600,7 @@ fabric.Image.filters.Tint.fromObject = function(object) {
|
|
13555
13600
|
*/
|
13556
13601
|
setFontsize: function(value) {
|
13557
13602
|
this.set('fontSize', value);
|
13603
|
+
this._initDimensions();
|
13558
13604
|
this.setCoords();
|
13559
13605
|
return this;
|
13560
13606
|
},
|
@@ -13577,6 +13623,7 @@ fabric.Image.filters.Tint.fromObject = function(object) {
|
|
13577
13623
|
*/
|
13578
13624
|
setText: function(value) {
|
13579
13625
|
this.set('text', value);
|
13626
|
+
this._initDimensions();
|
13580
13627
|
this.setCoords();
|
13581
13628
|
return this;
|
13582
13629
|
},
|
@@ -13589,19 +13636,11 @@ fabric.Image.filters.Tint.fromObject = function(object) {
|
|
13589
13636
|
* @return {fabric.Text} thisArg
|
13590
13637
|
* @chainable
|
13591
13638
|
*/
|
13592
|
-
|
13593
|
-
if (
|
13594
|
-
|
13595
|
-
this.set(prop, name[prop]);
|
13596
|
-
}
|
13639
|
+
_set: function(name, value) {
|
13640
|
+
if (name === 'fontFamily' && this.path) {
|
13641
|
+
this.path = this.path.replace(/(.*?)([^\/]*)(\.font\.js)/, '$1' + value + '$3');
|
13597
13642
|
}
|
13598
|
-
|
13599
|
-
this[name] = value;
|
13600
|
-
if (name === 'fontFamily' && this.path) {
|
13601
|
-
this.path = this.path.replace(/(.*?)([^\/]*)(\.font\.js)/, '$1' + value + '$3');
|
13602
|
-
}
|
13603
|
-
}
|
13604
|
-
return this;
|
13643
|
+
this.callSuper('_set', name, value);
|
13605
13644
|
}
|
13606
13645
|
});
|
13607
13646
|
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: fabric-rails
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0.
|
4
|
+
version: 0.0.8
|
5
5
|
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -9,11 +9,11 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date: 2012-09-
|
12
|
+
date: 2012-09-19 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: railties
|
16
|
-
requirement: &
|
16
|
+
requirement: &70348217761760 !ruby/object:Gem::Requirement
|
17
17
|
none: false
|
18
18
|
requirements:
|
19
19
|
- - ! '>='
|
@@ -24,10 +24,10 @@ dependencies:
|
|
24
24
|
version: '5.0'
|
25
25
|
type: :runtime
|
26
26
|
prerelease: false
|
27
|
-
version_requirements: *
|
27
|
+
version_requirements: *70348217761760
|
28
28
|
- !ruby/object:Gem::Dependency
|
29
29
|
name: thor
|
30
|
-
requirement: &
|
30
|
+
requirement: &70348217896960 !ruby/object:Gem::Requirement
|
31
31
|
none: false
|
32
32
|
requirements:
|
33
33
|
- - ~>
|
@@ -35,7 +35,7 @@ dependencies:
|
|
35
35
|
version: '0.14'
|
36
36
|
type: :runtime
|
37
37
|
prerelease: false
|
38
|
-
version_requirements: *
|
38
|
+
version_requirements: *70348217896960
|
39
39
|
description: This gem provides fabric.js for your Rails 3 application via the asset
|
40
40
|
pipeline.
|
41
41
|
email:
|