Build dist, fix lint errors

This commit is contained in:
Juriy Zaytsev 2015-12-24 10:57:55 -05:00
parent 7fc9d307af
commit 5d0524a6bd
9 changed files with 532 additions and 418 deletions

566
dist/fabric.js vendored
View file

@ -351,6 +351,7 @@ fabric.Collection = {
atan2 = Math.atan2,
atan = Math.atan,
pow = Math.pow,
abs = Math.abs,
PiBy180 = Math.PI / 180;
/**
@ -420,11 +421,29 @@ fabric.Collection = {
*/
rotatePoint: function(point, origin, radians) {
point.subtractEquals(origin);
var v = fabric.util.rotateVector(point, radians);
return new fabric.Point(v.x, v.y).addEquals(origin);
},
/**
* Rotates `vector` with `radians`
* @static
* @memberOf fabric.util
* @param {Object} vector The vector to rotate
* @param {Object.x} x coordinate of vector
* @param {Object.y} y coordinate of vector
* @param {Number} radians The radians of the angle for the rotation
* @return {Object} The new rotated point
*/
rotateVector: function(vector, radians) {
var sin = Math.sin(radians),
cos = Math.cos(radians),
rx = point.x * cos - point.y * sin,
ry = point.x * sin + point.y * cos;
return new fabric.Point(rx, ry).addEquals(origin);
rx = vector.x * cos - vector.y * sin,
ry = vector.x * sin + vector.y * cos;
return {
x: rx,
y: ry
};
},
/**
@ -614,7 +633,7 @@ fabric.Collection = {
// https://github.com/kangax/fabric.js/commit/d0abb90f1cd5c5ef9d2a94d3fb21a22330da3e0a#commitcomment-4513767
// see https://code.google.com/p/chromium/issues/detail?id=315152
// https://bugzilla.mozilla.org/show_bug.cgi?id=935069
if (url.indexOf('data') !== 0 && typeof crossOrigin !== 'undefined') {
if (url.indexOf('data') !== 0 && crossOrigin) {
img.crossOrigin = crossOrigin;
}
@ -852,20 +871,38 @@ fabric.Collection = {
* @return {Object} Components of transform
*/
qrDecompose: function(a) {
var angle = atan(a[0] / a[1]),
denom = pow(a[0]) + pow(a[1]),
var angle = atan2(a[1], a[0]),
denom = pow(a[0], 2) + pow(a[1], 2),
scaleX = sqrt(denom),
scaleY = (a[0] * a[3] - a[2] * a [1]) / scaleX,
skewX = atan((a[0] * a[2] + a[1] * a [3]) / denom);
skewX = atan2(a[0] * a[2] + a[1] * a [3], denom);
return {
angle: angle / PiBy180,
angle: angle / PiBy180,
scaleX: scaleX,
scaleY: scaleY,
skewX: skewX / PiBy180,
skewY: 0
skewY: 0,
translateX: a[4],
translateY: a[5]
};
},
customTransformMatrix: function(scaleX, scaleY, skewX) {
var skewMatrixX = [1, 0, abs(Math.tan(skewX * PiBy180)), 1],
scaleMatrix = [abs(scaleX), 0, 0, abs(scaleY)];
return fabric.util.multiplyTransformMatrices(scaleMatrix, skewMatrixX, true);
},
resetObjectTransform: function (target) {
target.scaleX = 1;
target.scaleY = 1;
target.skewX = 0;
target.skewY = 0;
target.flipX = false;
target.flipY = false;
target.setAngle(0);
},
/**
* Returns string representation of function body
* @param {Function} fn Function to get body of
@ -2993,10 +3030,17 @@ if (typeof console !== 'undefined') {
function _setStrokeFillOpacity(attributes) {
for (var attr in colorAttributes) {
if (!attributes[attr] || typeof attributes[colorAttributes[attr]] === 'undefined') {
if (typeof attributes[colorAttributes[attr]] === 'undefined') {
continue;
}
if (!attributes[attr]) {
if (!fabric.Object.prototype[attr]) {
continue;
}
attributes[attr] = fabric.Object.prototype[attr];
}
if (attributes[attr].indexOf('url(') === 0) {
continue;
}
@ -3017,12 +3061,16 @@ if (typeof console !== 'undefined') {
*/
fabric.parseTransformAttribute = (function() {
function rotateMatrix(matrix, args) {
var angle = args[0];
var angle = args[0],
x = (args.length === 3) ? args[1] : 0,
y = (args.length === 3) ? args[2] : 0;
matrix[0] = Math.cos(angle);
matrix[1] = Math.sin(angle);
matrix[2] = -Math.sin(angle);
matrix[3] = Math.cos(angle);
matrix[4] = x - (matrix[0] * x + matrix[2] * y);
matrix[5] = y - (matrix[1] * x + matrix[3] * y);
}
function scaleMatrix(matrix, args) {
@ -5687,21 +5735,24 @@ fabric.Pattern = fabric.util.createClass(/** @lends fabric.Pattern.prototype */
* @return {String} SVG representation of a shadow
*/
toSVG: function(object) {
var fBoxX = 40, fBoxY = 40;
var fBoxX = 40, fBoxY = 40, NUM_FRACTION_DIGITS = fabric.Object.NUM_FRACTION_DIGITS,
offset = fabric.util.rotateVector({x: this.offsetX, y: this.offsetY},
fabric.util.degreesToRadians(-object.angle)), BLUR_BOX = 20;
if (object.width && object.height) {
//http://www.w3.org/TR/SVG/filters.html#FilterEffectsRegion
// we add some extra space to filter box to contain the blur ( 20 )
fBoxX = toFixed((Math.abs(this.offsetX) + this.blur) / object.width, 2) * 100 + 20;
fBoxY = toFixed((Math.abs(this.offsetY) + this.blur) / object.height, 2) * 100 + 20;
fBoxX = toFixed((Math.abs(offset.x) + this.blur) / object.width, NUM_FRACTION_DIGITS) * 100 + BLUR_BOX;
fBoxY = toFixed((Math.abs(offset.y) + this.blur) / object.height, NUM_FRACTION_DIGITS) * 100 + BLUR_BOX;
}
return (
'<filter id="SVGID_' + this.id + '" y="-' + fBoxY + '%" height="' + (100 + 2 * fBoxY) + '%" ' +
'x="-' + fBoxX + '%" width="' + (100 + 2 * fBoxX) + '%" ' + '>\n' +
'\t<feGaussianBlur in="SourceAlpha" stdDeviation="' +
toFixed(this.blur ? this.blur / 2 : 0, 3) + '"></feGaussianBlur>\n' +
'\t<feOffset dx="' + this.offsetX + '" dy="' + this.offsetY + '" result="oBlur" ></feOffset>\n' +
toFixed(this.blur ? this.blur / 2 : 0, NUM_FRACTION_DIGITS) + '"></feGaussianBlur>\n' +
'\t<feOffset dx="' + toFixed(offset.x, NUM_FRACTION_DIGITS) +
'" dy="' + toFixed(offset.y, NUM_FRACTION_DIGITS) + '" result="oBlur" ></feOffset>\n' +
'\t<feFlood flood-color="' + this.color + '"/>\n' +
'\t<feComposite in2="oBlur" operator="in" />\n' +
'\t<feMerge>\n' +
@ -5722,22 +5773,18 @@ fabric.Pattern = fabric.util.createClass(/** @lends fabric.Pattern.prototype */
color: this.color,
blur: this.blur,
offsetX: this.offsetX,
offsetY: this.offsetY
offsetY: this.offsetY,
affectStroke: this.affectStroke
};
}
var obj = { }, proto = fabric.Shadow.prototype;
if (this.color !== proto.color) {
obj.color = this.color;
}
if (this.blur !== proto.blur) {
obj.blur = this.blur;
}
if (this.offsetX !== proto.offsetX) {
obj.offsetX = this.offsetX;
}
if (this.offsetY !== proto.offsetY) {
obj.offsetY = this.offsetY;
}
['color', 'blur', 'offsetX', 'offsetY', 'affectStroke'].forEach(function(prop) {
if (this[prop] !== proto[prop]) {
obj[prop] = this[prop];
}
}, this);
return obj;
}
});
@ -5766,6 +5813,7 @@ fabric.Pattern = fabric.util.createClass(/** @lends fabric.Pattern.prototype */
var extend = fabric.util.object.extend,
getElementOffset = fabric.util.getElementOffset,
removeFromArray = fabric.util.removeFromArray,
toFixed = fabric.util.toFixed,
CANVAS_INIT_ERROR = new Error('Could not initialize `canvas` element');
@ -6332,7 +6380,7 @@ fabric.Pattern = fabric.util.createClass(/** @lends fabric.Pattern.prototype */
this._setCssDimension(prop, cssValue);
}
}
this._initRetinaScaling();
this._setImageSmoothing();
this.calcOffset();
@ -6619,30 +6667,29 @@ fabric.Pattern = fabric.util.createClass(/** @lends fabric.Pattern.prototype */
if (this.clipTo) {
fabric.util.clipContext(this, canvasToDrawOn);
}
objsToRender = this._chooseObjectsToRender();
//apply viewport transform once for all rendering process
canvasToDrawOn.setTransform.apply(canvasToDrawOn, this.viewportTransform);
this._renderBackground(canvasToDrawOn);
canvasToDrawOn.save();
objsToRender = this._chooseObjectsToRender();
//apply viewport transform once for all rendering process
canvasToDrawOn.transform.apply(canvasToDrawOn, this.viewportTransform);
this._renderObjects(canvasToDrawOn, objsToRender);
this.preserveObjectStacking || this._renderObjects(canvasToDrawOn, [this.getActiveGroup()]);
canvasToDrawOn.restore();
if (!this.controlsAboveOverlay && this.interactive) {
this.drawControls(canvasToDrawOn);
}
if (this.clipTo) {
canvasToDrawOn.restore();
}
this._renderOverlay(canvasToDrawOn);
if (this.controlsAboveOverlay && this.interactive) {
this.drawControls(canvasToDrawOn);
}
this.fire('after:render');
canvasToDrawOn.setTransform.apply(canvasToDrawOn, [1, 0, 0, 1, 0, 0]);
canvasToDrawOn.restore();
return this;
},
@ -6939,6 +6986,8 @@ fabric.Pattern = fabric.util.createClass(/** @lends fabric.Pattern.prototype */
* @param {Number} [options.viewBox.width] Width of viewbox
* @param {Number} [options.viewBox.height] Height of viewbox
* @param {String} [options.encoding=UTF-8] Encoding of SVG output
* @param {String} [options.width] desired width of svg with or without units
* @param {String} [options.height] desired height of svg with or without units
* @param {Function} [reviver] Method for further parsing of svg elements, called after each fabric object converted into svg representation.
* @return {String} SVG string
* @tutorial {@link http://fabricjs.com/fabric-intro-part-3/#serialization}
@ -6988,32 +7037,40 @@ fabric.Pattern = fabric.util.createClass(/** @lends fabric.Pattern.prototype */
* @private
*/
_setSVGPreamble: function(markup, options) {
if (!options.suppressPreamble) {
markup.push(
'<?xml version="1.0" encoding="', (options.encoding || 'UTF-8'), '" standalone="no" ?>\n',
'<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" ',
'"http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">\n'
);
if (options.suppressPreamble) {
return;
}
markup.push(
'<?xml version="1.0" encoding="', (options.encoding || 'UTF-8'), '" standalone="no" ?>\n',
'<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" ',
'"http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">\n'
);
},
/**
* @private
*/
_setSVGHeader: function(markup, options) {
var width, height, vpt;
var width = options.width || this.width,
height = options.height || this.height,
vpt, viewBox = 'viewBox="0 0 ' + this.width + ' ' + this.height + '" ',
NUM_FRACTION_DIGITS = fabric.Object.NUM_FRACTION_DIGITS;
if (options.viewBox) {
width = options.viewBox.width;
height = options.viewBox.height;
viewBox = 'viewBox="' +
options.viewBox.x + ' ' +
options.viewBox.y + ' ' +
options.viewBox.width + ' ' +
options.viewBox.height + '" ';
}
else {
width = this.width;
height = this.height;
if (!this.svgViewportTransformation) {
if (this.svgViewportTransformation) {
vpt = this.viewportTransform;
width /= vpt[0];
height /= vpt[3];
viewBox = 'viewBox="' +
toFixed(-vpt[4] / vpt[0], NUM_FRACTION_DIGITS) + ' ' +
toFixed(-vpt[5] / vpt[3], NUM_FRACTION_DIGITS) + ' ' +
toFixed(this.width / vpt[0], NUM_FRACTION_DIGITS) + ' ' +
toFixed(this.height / vpt[3], NUM_FRACTION_DIGITS) + '" ';
}
}
@ -7027,13 +7084,7 @@ fabric.Pattern = fabric.util.createClass(/** @lends fabric.Pattern.prototype */
(this.backgroundColor && !this.backgroundColor.toLive
? 'style="background-color: ' + this.backgroundColor + '" '
: null),
(options.viewBox
? 'viewBox="' +
options.viewBox.x + ' ' +
options.viewBox.y + ' ' +
options.viewBox.width + ' ' +
options.viewBox.height + '" '
: null),
viewBox,
'xml:space="preserve">\n',
'<desc>Created with Fabric.js ', fabric.version, '</desc>\n',
'<defs>',
@ -9218,7 +9269,7 @@ fabric.PatternBrush = fabric.util.createClass(fabric.PencilBrush, /** @lends fab
},
/**
* Sets active group to a speicified one
* Sets active group to a specified one
* @param {fabric.Group} group Group to set as a current one
* @return {fabric.Canvas} thisArg
* @chainable
@ -9298,16 +9349,14 @@ fabric.PatternBrush = fabric.util.createClass(fabric.PencilBrush, /** @lends fab
* @param {CanvasRenderingContext2D} ctx Context to render controls on
*/
drawControls: function(ctx) {
ctx.save();
ctx.setTransform.apply(ctx, [1, 0, 0, 1, 0, 0]);
var activeGroup = this.getActiveGroup();
if (activeGroup) {
activeGroup._renderControls(ctx);
}
else {
this._drawObjectsControls(ctx);
}
ctx.restore();
},
/**
@ -10153,7 +10202,6 @@ fabric.PatternBrush = fabric.util.createClass(fabric.PencilBrush, /** @lends fab
if (activeGroup.contains(target)) {
activeGroup.removeWithUpdate(target);
this._resetObjectTransform(activeGroup);
target.set('active', false);
if (activeGroup.size() === 1) {
@ -10166,7 +10214,6 @@ fabric.PatternBrush = fabric.util.createClass(fabric.PencilBrush, /** @lends fab
}
else {
activeGroup.addWithUpdate(target);
this._resetObjectTransform(activeGroup);
}
this.fire('selection:created', { target: activeGroup, e: e });
activeGroup.set('active', true);
@ -11814,22 +11861,22 @@ fabric.util.object.extend(fabric.StaticCanvas.prototype, /** @lends fabric.Stati
if (!this.active || noTransform) {
return;
}
var vpt = this.getViewportTransform();
var vpt = this.getViewportTransform(),
matrix = this.calcTransformMatrix(),
options;
matrix = fabric.util.multiplyTransformMatrices(vpt, matrix);
options = fabric.util.qrDecompose(matrix);
ctx.save();
var center;
if (this.group) {
center = fabric.util.transformPoint(this.group.getCenterPoint(), vpt);
ctx.translate(center.x, center.y);
ctx.rotate(degreesToRadians(this.group.angle));
ctx.translate(options.translateX, options.translateY);
if (this.group && this.group === this.canvas.getActiveGroup()) {
ctx.rotate(degreesToRadians(options.angle));
this.drawBordersInGroup(ctx, options);
}
center = fabric.util.transformPoint(this.getCenterPoint(), vpt, null != this.group);
if (this.group) {
center.x *= this.group.scaleX;
center.y *= this.group.scaleY;
else {
ctx.rotate(degreesToRadians(this.angle));
this.drawBorders(ctx);
}
ctx.translate(center.x, center.y);
ctx.rotate(degreesToRadians(this.angle));
this.drawBorders(ctx);
this.drawControls(ctx);
ctx.restore();
},
@ -12536,7 +12583,8 @@ fabric.util.object.extend(fabric.StaticCanvas.prototype, /** @lends fabric.Stati
];
}
var degreesToRadians = fabric.util.degreesToRadians;
var degreesToRadians = fabric.util.degreesToRadians,
multiplyMatrices = fabric.util.multiplyTransformMatrices;
fabric.util.object.extend(fabric.Object.prototype, /** @lends fabric.Object.prototype */ {
@ -12873,12 +12921,34 @@ fabric.util.object.extend(fabric.StaticCanvas.prototype, /** @lends fabric.Stati
return this;
},
_calcDimensionsTransformMatrix: function(skewX, skewY) {
var skewMatrixX = [1, 0, Math.tan(degreesToRadians(skewX)), 1, 0, 0],
skewMatrixY = [1, Math.tan(degreesToRadians(skewY)), 0, 1, 0, 0],
scaleMatrix = [this.scaleX, 0, 0, this.scaleY, 0, 0],
m = fabric.util.multiplyTransformMatrices(scaleMatrix, skewMatrixX, true);
return fabric.util.multiplyTransformMatrices(m, skewMatrixY, true);
_calcRotateMatrix: function() {
if (this.angle) {
var theta = degreesToRadians(this.angle), cos = Math.cos(theta), sin = Math.sin(theta);
return [cos, sin, -sin, cos, 0, 0];
}
return [1, 0, 0, 1, 0, 0];
},
calcTransformMatrix: function() {
var center = this.getCenterPoint(),
translateMatrix = [1, 0, 0, 1, center.x, center.y],
rotateMatrix = this._calcRotateMatrix(),
dimensionMatrix = this._calcDimensionsTransformMatrix(this.skewX, this.skewY, true),
matrix = this.group ? this.group.calcTransformMatrix() : [1, 0, 0, 1, 0, 0];
matrix = multiplyMatrices(matrix, translateMatrix);
matrix = multiplyMatrices(matrix, rotateMatrix);
matrix = multiplyMatrices(matrix, dimensionMatrix);
return matrix;
},
_calcDimensionsTransformMatrix: function(skewX, skewY, flipping) {
var skewMatrixX = [1, 0, Math.tan(degreesToRadians(skewX)), 1],
skewMatrixY = [1, Math.tan(degreesToRadians(skewY)), 0, 1],
scaleX = this.scaleX * (flipping && this.flipX ? -1 : 1),
scaleY = this.scaleY * (flipping && this.flipY ? -1 : 1),
scaleMatrix = [scaleX, 0, 0, scaleY],
m = multiplyMatrices(scaleMatrix, skewMatrixX, true);
return multiplyMatrices(m, skewMatrixY, true);
}
});
})();
@ -13028,8 +13098,7 @@ fabric.util.object.extend(fabric.Object.prototype, /** @lends fabric.Object.prot
angle = this.getAngle(),
skewX = (this.getSkewX() % 360),
skewY = (this.getSkewY() % 360),
vpt = !this.canvas || this.canvas.svgViewportTransformation ? this.getViewportTransform() : [1, 0, 0, 1, 0, 0],
center = fabric.util.transformPoint(this.getCenterPoint(), vpt),
center = this.getCenterPoint(),
NUM_FRACTION_DIGITS = fabric.Object.NUM_FRACTION_DIGITS,
@ -13043,23 +13112,23 @@ fabric.util.object.extend(fabric.Object.prototype, /** @lends fabric.Object.prot
? (' rotate(' + toFixed(angle, NUM_FRACTION_DIGITS) + ')')
: '',
scalePart = (this.scaleX === 1 && this.scaleY === 1 && vpt[0] === 1 && vpt[3] === 1)
scalePart = (this.scaleX === 1 && this.scaleY === 1)
? '' :
(' scale(' +
toFixed(this.scaleX * vpt[0], NUM_FRACTION_DIGITS) +
toFixed(this.scaleX, NUM_FRACTION_DIGITS) +
' ' +
toFixed(this.scaleY * vpt[3], NUM_FRACTION_DIGITS) +
toFixed(this.scaleY, NUM_FRACTION_DIGITS) +
')'),
skewXPart = skewX !== 0 ? ' skewX(' + toFixed(skewX, NUM_FRACTION_DIGITS) + ')' : '',
skewYPart = skewY !== 0 ? ' skewY(' + toFixed(skewY, NUM_FRACTION_DIGITS) + ')' : '',
addTranslateX = this.type === 'path-group' ? this.width * vpt[0] : 0,
addTranslateX = this.type === 'path-group' ? this.width : 0,
flipXPart = this.flipX ? ' matrix(-1 0 0 1 ' + addTranslateX + ' 0) ' : '',
addTranslateY = this.type === 'path-group' ? this.height * vpt[3] : 0,
addTranslateY = this.type === 'path-group' ? this.height : 0,
flipYPart = this.flipY ? ' matrix(1 0 0 -1 0 ' + addTranslateY + ')' : '';
@ -13310,7 +13379,7 @@ fabric.util.object.extend(fabric.Object.prototype, /** @lends fabric.Object.prot
x: dimX,
y: dimY
}],
i, transformMatrix = this._calcDimensionsTransformMatrix(skewX, skewY),
i, transformMatrix = this._calcDimensionsTransformMatrix(skewX, skewY, false),
bbox;
for (i = 0; i < points.length; i++) {
points[i] = fabric.util.transformPoint(points[i], transformMatrix);
@ -13346,25 +13415,21 @@ fabric.util.object.extend(fabric.Object.prototype, /** @lends fabric.Object.prot
return this;
}
ctx.save();
var wh = this._calculateCurrentDimensions(),
strokeWidth = 1 / this.borderScaleFactor,
width = wh.x + strokeWidth,
height = wh.y + strokeWidth;
ctx.save();
ctx.globalAlpha = this.isMoving ? this.borderOpacityWhenMoving : 1;
ctx.strokeStyle = this.borderColor;
ctx.lineWidth = 1 / this.borderScaleFactor;
var wh = this._calculateCurrentDimensions(),
width = wh.x,
height = wh.y;
if (this.group) {
width = width * this.group.scaleX;
height = height * this.group.scaleY;
}
ctx.lineWidth = strokeWidth;
ctx.strokeRect(
~~(-(width / 2)) - 0.5, // offset needed to make lines look sharper
~~(-(height / 2)) - 0.5,
~~(width) + 1, // double offset needed to make lines look sharper
~~(height) + 1
-width / 2,
-height / 2,
width,
height
);
if (this.hasRotatingPoint && this.isControlVisible('mtr') && !this.get('lockRotation') && this.hasControls) {
@ -13382,6 +13447,44 @@ fabric.util.object.extend(fabric.Object.prototype, /** @lends fabric.Object.prot
return this;
},
/**
* Draws borders of an object's bounding box when it is inside a group.
* Requires public properties: width, height
* Requires public options: padding, borderColor
* @param {CanvasRenderingContext2D} ctx Context to draw on
* @param {object} options object representing current object parameters
* @return {fabric.Object} thisArg
* @chainable
*/
drawBordersInGroup: function(ctx, options) {
if (!this.hasBorders) {
return this;
}
var p = this._getNonTransformedDimensions(),
matrix = fabric.util.customTransformMatrix(options.scaleX, options.scaleY, options.skewX),
wh = fabric.util.transformPoint(p, matrix),
strokeWidth = 1 / this.borderScaleFactor,
width = wh.x + strokeWidth + 2 * this.padding,
height = wh.y + strokeWidth + 2 * this.padding;
ctx.save();
ctx.globalAlpha = this.isMoving ? this.borderOpacityWhenMoving : 1;
ctx.strokeStyle = this.borderColor;
ctx.lineWidth = strokeWidth;
ctx.strokeRect(
-width / 2,
-height / 2,
width,
height
);
ctx.restore();
return this;
},
/**
* Draws corners of an object's bounding box.
* Requires public properties: width, height
@ -13398,9 +13501,9 @@ fabric.util.object.extend(fabric.Object.prototype, /** @lends fabric.Object.prot
var wh = this._calculateCurrentDimensions(),
width = wh.x,
height = wh.y,
scaleOffset = this.cornerSize / 2,
left = -(width / 2) - scaleOffset,
top = -(height / 2) - scaleOffset,
scaleOffset = this.cornerSize,
left = -(width + scaleOffset) / 2,
top = -(height + scaleOffset) / 2,
methodName = this.transparentCorners ? 'strokeRect' : 'fillRect';
ctx.save();
@ -13456,7 +13559,7 @@ fabric.util.object.extend(fabric.Object.prototype, /** @lends fabric.Object.prot
// middle-top-rotate
if (this.hasRotatingPoint) {
this._drawControl('mtr', ctx, methodName,
left + width/2 ,
left + width / 2,
top - this.rotatingPointOffset);
}
@ -16767,6 +16870,7 @@ fabric.util.object.extend(fabric.Object.prototype, /** @lends fabric.Object.prot
*/
addWithUpdate: function(object) {
this._restoreObjectsState();
fabric.util.resetObjectTransform(this);
if (object) {
this._objects.push(object);
object.group = this;
@ -16794,9 +16898,8 @@ fabric.util.object.extend(fabric.Object.prototype, /** @lends fabric.Object.prot
* @chainable
*/
removeWithUpdate: function(object) {
this._moveFlippedObject(object);
this._restoreObjectsState();
fabric.util.resetObjectTransform(this);
// since _restoreObjectsState set objects inactive
this.forEachObject(this._setObjectActive, this);
@ -16829,7 +16932,8 @@ fabric.util.object.extend(fabric.Object.prototype, /** @lends fabric.Object.prot
*/
delegatedProperties: {
fill: true,
opacity: true,
stroke: true,
strokeWidth: true,
fontFamily: true,
fontWeight: true,
fontSize: true,
@ -16945,59 +17049,20 @@ fabric.util.object.extend(fabric.Object.prototype, /** @lends fabric.Object.prot
* @return {fabric.Object} transformedObject
*/
realizeTransform: function(object) {
this._moveFlippedObject(object);
this._setObjectPosition(object);
var matrix = object.calcTransformMatrix(),
options = fabric.util.qrDecompose(matrix),
center = new fabric.Point(options.translateX, options.translateY);
object.scaleX = options.scaleX;
object.scaleY = options.scaleY;
object.skewX = options.skewX;
object.skewY = options.skewY;
object.angle = options.angle;
object.flipX = false;
object.flipY = false;
object.setPositionByOrigin(center, 'center', 'center');
return object;
},
/**
* Moves a flipped object to the position where it's displayed
* @private
* @param {fabric.Object} object
* @return {fabric.Group} thisArg
*/
_moveFlippedObject: function(object) {
var oldOriginX = object.get('originX'),
oldOriginY = object.get('originY'),
center = object.getCenterPoint();
object.set({
originX: 'center',
originY: 'center',
left: center.x,
top: center.y
});
this._toggleFlipping(object);
var newOrigin = object.getPointByOrigin(oldOriginX, oldOriginY);
object.set({
originX: oldOriginX,
originY: oldOriginY,
left: newOrigin.x,
top: newOrigin.y
});
return this;
},
/**
* @private
*/
_toggleFlipping: function(object) {
if (this.flipX) {
object.toggle('flipX');
object.set('left', -object.get('left'));
object.setAngle(-object.getAngle());
}
if (this.flipY) {
object.toggle('flipY');
object.set('top', -object.get('top'));
object.setAngle(-object.getAngle());
}
},
/**
* Restores original state of a specified object in group
* @private
@ -17005,55 +17070,22 @@ fabric.util.object.extend(fabric.Object.prototype, /** @lends fabric.Object.prot
* @return {fabric.Group} thisArg
*/
_restoreObjectState: function(object) {
this._setObjectPosition(object);
this.realizeTransform(object);
object.setCoords();
object.hasControls = object.__origHasControls;
delete object.__origHasControls;
object.set('active', false);
object.setCoords();
delete object.group;
return this;
},
/**
* @private
*/
_setObjectPosition: function(object) {
var center = this.getCenterPoint(),
rotated = this._getRotatedLeftTop(object);
object.set({
angle: object.getAngle() + this.getAngle(),
left: center.x + rotated.left,
top: center.y + rotated.top,
scaleX: object.get('scaleX') * this.get('scaleX'),
scaleY: object.get('scaleY') * this.get('scaleY')
});
},
/**
* @private
*/
_getRotatedLeftTop: function(object) {
var groupAngle = this.getAngle() * (Math.PI / 180);
return {
left: (-Math.sin(groupAngle) * object.getTop() * this.get('scaleY') +
Math.cos(groupAngle) * object.getLeft() * this.get('scaleX')),
top: (Math.cos(groupAngle) * object.getTop() * this.get('scaleY') +
Math.sin(groupAngle) * object.getLeft() * this.get('scaleX'))
};
},
/**
* Destroys a group (restoring state of its objects)
* @return {fabric.Group} thisArg
* @chainable
*/
destroy: function() {
this._objects.forEach(this._moveFlippedObject, this);
return this._restoreObjectsState();
},
@ -17294,6 +17326,14 @@ fabric.util.object.extend(fabric.Object.prototype, /** @lends fabric.Object.prot
*/
meetOrSlice: 'meet',
/**
* Width of a stroke.
* For image quality a stroke multiple of 2 gives better results.
* @type Number
* @default
*/
strokeWidth: 0,
/**
* private
* contains last value of scaleX to detect
@ -18158,16 +18198,6 @@ fabric.Image.filters.BaseFilter = fabric.util.createClass(/** @lends fabric.Imag
0, 1, 0,
0, 0, 0
];
var canvasEl = fabric.util.createCanvasElement();
this.tmpCtx = canvasEl.getContext('2d');
},
/**
* @private
*/
_createImageData: function(w, h) {
return this.tmpCtx.createImageData(w, h);
},
/**
@ -18185,39 +18215,32 @@ fabric.Image.filters.BaseFilter = fabric.util.createClass(/** @lends fabric.Imag
src = pixels.data,
sw = pixels.width,
sh = pixels.height,
// pad output by the convolution matrix
w = sw,
h = sh,
output = this._createImageData(w, h),
output = context.createImageData(sw, sh),
dst = output.data,
// go through the destination image pixels
alphaFac = this.opaque ? 1 : 0;
alphaFac = this.opaque ? 1 : 0,
r, g, b, a, dstOff,
scx, scy, srcOff, wt;
for (var y = 0; y < h; y++) {
for (var x = 0; x < w; x++) {
var sy = y,
sx = x,
dstOff = (y * w + x) * 4,
for (var y = 0; y < sh; y++) {
for (var x = 0; x < sw; x++) {
dstOff = (y * sw + x) * 4;
// calculate the weighed sum of the source image pixels that
// fall under the convolution matrix
r = 0, g = 0, b = 0, a = 0;
r = 0; g = 0; b = 0; a = 0;
for (var cy = 0; cy < side; cy++) {
for (var cx = 0; cx < side; cx++) {
var scy = sy + cy - halfSide,
scx = sx + cx - halfSide;
scy = y + cy - halfSide;
scx = x + cx - halfSide;
/* jshint maxdepth:5 */
if (scy < 0 || scy > sh || scx < 0 || scx > sw) {
continue;
}
var srcOff = (scy * sw + scx) * 4,
wt = weights[cy * side + cx];
srcOff = (scy * sw + scx) * 4;
wt = weights[cy * side + cx];
r += src[srcOff] * wt;
g += src[srcOff + 1] * wt;
@ -20155,11 +20178,12 @@ fabric.Image.filters.BaseFilter = fabric.util.createClass(/** @lends fabric.Imag
// stretch the line
var words = line.split(/\s+/),
wordsWidth = this._getWidthOfWords(ctx, line, lineIndex),
charOffset = 0,
wordsWidth = this._getWidthOfWords(ctx, line, lineIndex, 0),
widthDiff = this.width - wordsWidth,
numSpaces = words.length - 1,
spaceWidth = numSpaces > 0 ? widthDiff / numSpaces : 0,
leftOffset = 0, charOffset = 0, word;
leftOffset = 0, word;
for (var i = 0, len = words.length; i < len; i++) {
while (line[charOffset] === ' ' && charOffset < line.length) {
@ -20167,7 +20191,7 @@ fabric.Image.filters.BaseFilter = fabric.util.createClass(/** @lends fabric.Imag
}
word = words[i];
this._renderChars(method, ctx, word, left + leftOffset, top, lineIndex, charOffset);
leftOffset += ctx.measureText(word).width + spaceWidth;
leftOffset += this._getWidthOfWords(ctx, word, lineIndex, charOffset) + spaceWidth;
charOffset += word.length;
}
},
@ -20316,7 +20340,7 @@ fabric.Image.filters.BaseFilter = fabric.util.createClass(/** @lends fabric.Imag
ctx.fillStyle = this.textBackgroundColor;
for (var i = 0, len = this._textLines.length; i < len; i++) {
if (this._textLines[i] !== '') {
lineWidth = this._getLineWidth(ctx, i);
lineWidth = this.textAlign === 'justify' ? this.width : this._getLineWidth(ctx, i);
lineLeftOffset = this._getLineLeftOffset(lineWidth);
ctx.fillRect(
this._getLeftOffset() + lineLeftOffset,
@ -20385,7 +20409,7 @@ fabric.Image.filters.BaseFilter = fabric.util.createClass(/** @lends fabric.Imag
width = 0;
}
else if (this.textAlign === 'justify' && this._cacheLinesWidth) {
wordCount = line.split(' ');
wordCount = line.split(/\s+/);
//consider not justify last line, not for now.
if (wordCount.length > 1) {
width = this.width;
@ -20565,9 +20589,9 @@ fabric.Image.filters.BaseFilter = fabric.util.createClass(/** @lends fabric.Imag
(this.fontStyle ? 'font-style="' + this.fontStyle + '" ': ''),
(this.fontWeight ? 'font-weight="' + this.fontWeight + '" ': ''),
(this.textDecoration ? 'text-decoration="' + this.textDecoration + '" ': ''),
'style="', this.getSvgStyles(), '" >',
'style="', this.getSvgStyles(), '" >\n',
textAndBg.textSpans.join(''),
'</text>\n',
'\t\t</text>\n',
'\t</g>\n'
);
},
@ -20603,8 +20627,13 @@ fabric.Image.filters.BaseFilter = fabric.util.createClass(/** @lends fabric.Imag
_setSVGTextLineText: function(i, textSpans, height, textLeftOffset, textTopOffset) {
var yPos = this.fontSize * (this._fontSizeMult - this._fontSizeFraction)
- textTopOffset + height - this.height / 2;
if (this.textAlign === 'justify') {
// i call from here to do not intefere with IText
this._setSVGTextLineJustifed(i, textSpans, yPos, textLeftOffset);
return;
}
textSpans.push(
'<tspan x="',
'\t\t\t<tspan x="',
toFixed(textLeftOffset + this._getLineLeftOffset(this._getLineWidth(this.ctx, i)), NUM_FRACTION_DIGITS), '" ',
'y="',
toFixed(yPos, NUM_FRACTION_DIGITS),
@ -20613,10 +20642,40 @@ fabric.Image.filters.BaseFilter = fabric.util.createClass(/** @lends fabric.Imag
// on containing <text> one doesn't work in Illustrator
this._getFillAttributes(this.fill), '>',
fabric.util.string.escapeXml(this._textLines[i]),
'</tspan>'
'</tspan>\n'
);
},
_setSVGTextLineJustifed: function(i, textSpans, yPos, textLeftOffset) {
var ctx = fabric.util.createCanvasElement().getContext('2d');
this._setTextStyles(ctx);
var line = this._textLines[i],
words = line.split(/\s+/),
wordsWidth = this._getWidthOfWords(ctx, line),
widthDiff = this.width - wordsWidth,
numSpaces = words.length - 1,
spaceWidth = numSpaces > 0 ? widthDiff / numSpaces : 0,
word, attributes = this._getFillAttributes(this.fill);
textLeftOffset += this._getLineLeftOffset(this._getLineWidth(ctx, i))
for (var i = 0, len = words.length; i < len; i++) {
word = words[i];
textSpans.push(
'\t\t\t<tspan x="',
toFixed(textLeftOffset, NUM_FRACTION_DIGITS), '" ',
'y="',
toFixed(yPos, NUM_FRACTION_DIGITS),
'" ',
// doing this on <tspan> elements since setting opacity
// on containing <text> one doesn't work in Illustrator
attributes, '>',
fabric.util.string.escapeXml(word),
'</tspan>\n'
);
textLeftOffset += this._getWidthOfWords(ctx, word) + spaceWidth;
}
},
_setSVGTextLineBg: function(textBgRects, i, textLeftOffset, textTopOffset, height) {
textBgRects.push(
'\t\t<rect ',
@ -20739,8 +20798,25 @@ fabric.Image.filters.BaseFilter = fabric.util.createClass(/** @lends fabric.Imag
if (!options.originX) {
options.originX = 'left';
}
var textContent = element.textContent.replace(/^\s+|\s+$|\n+/g, '').replace(/\s+/g, ' '),
text = new fabric.Text(textContent, options),
var textContent = '';
// The XML is not properly parsed in IE9 so a workaround to get
// textContent is through firstChild.data. Another workaround would be
// to convert XML loaded from a file to be converted using DOMParser (same way loadSVGFromString() does)
if (!('textContent' in element)) {
if ('firstChild' in element && element.firstChild !== null) {
if ('data' in element.firstChild && element.firstChild.data !== null) {
textContent = element.firstChild.data;
}
}
} else {
textContent = element.textContent;
}
textContent = textContent.replace(/^\s+|\s+$|\n+/g, '').replace(/\s+/g, ' ');
var text = new fabric.Text(textContent, options),
/*
Adjust positioning:
x/y attributes in SVG correspond to the bottom-left corner of text bounding box
@ -21789,7 +21865,7 @@ fabric.Image.filters.BaseFilter = fabric.util.createClass(/** @lends fabric.Imag
return this.__widthOfSpace[lineIndex];
}
var line = this._textLines[lineIndex],
wordsWidth = this._getWidthOfWords(ctx, line, lineIndex),
wordsWidth = this._getWidthOfWords(ctx, line, lineIndex, 0),
widthDiff = this.width - wordsWidth,
numSpaces = line.length - line.replace(this._reSpacesAndTabs, '').length,
width = widthDiff / numSpaces;
@ -21803,14 +21879,14 @@ fabric.Image.filters.BaseFilter = fabric.util.createClass(/** @lends fabric.Imag
* @param {Number} line
* @param {Number} lineIndex
*/
_getWidthOfWords: function (ctx, line, lineIndex) {
_getWidthOfWords: function (ctx, line, lineIndex, charOffset) {
var width = 0;
for (var charIndex = 0; charIndex < line.length; charIndex++) {
var _char = line[charIndex];
if (!_char.match(/\s/)) {
width += this._getWidthOfChar(ctx, _char, lineIndex, charIndex);
width += this._getWidthOfChar(ctx, _char, lineIndex, charIndex + charOffset);
}
}
@ -22748,7 +22824,9 @@ fabric.util.object.extend(fabric.IText.prototype, /** @lends fabric.IText.protot
*/
initMousedownHandler: function() {
this.on('mousedown', function(options) {
if (!this.editable) {
return;
}
var pointer = this.canvas.getPointer(options.e);
this.__mousedownX = pointer.x;
@ -22786,7 +22864,7 @@ fabric.util.object.extend(fabric.IText.prototype, /** @lends fabric.IText.protot
initMouseupHandler: function() {
this.on('mouseup', function(options) {
this.__isMousedown = false;
if (this._isObjectMoved(options.e)) {
if (!this.editable || this._isObjectMoved(options.e)) {
return;
}

16
dist/fabric.min.js vendored

File diff suppressed because one or more lines are too long

BIN
dist/fabric.min.js.gz vendored

Binary file not shown.

330
dist/fabric.require.js vendored
View file

@ -164,7 +164,7 @@ fabric.Collection = {
};
(function(global) {
var sqrt = Math.sqrt, atan2 = Math.atan2, atan = Math.atan, pow = Math.pow, PiBy180 = Math.PI / 180;
var sqrt = Math.sqrt, atan2 = Math.atan2, atan = Math.atan, pow = Math.pow, abs = Math.abs, PiBy180 = Math.PI / 180;
fabric.util = {
removeFromArray: function(array, value) {
var idx = array.indexOf(value);
@ -184,8 +184,15 @@ fabric.Collection = {
},
rotatePoint: function(point, origin, radians) {
point.subtractEquals(origin);
var sin = Math.sin(radians), cos = Math.cos(radians), rx = point.x * cos - point.y * sin, ry = point.x * sin + point.y * cos;
return new fabric.Point(rx, ry).addEquals(origin);
var v = fabric.util.rotateVector(point, radians);
return new fabric.Point(v.x, v.y).addEquals(origin);
},
rotateVector: function(vector, radians) {
var sin = Math.sin(radians), cos = Math.cos(radians), rx = vector.x * cos - vector.y * sin, ry = vector.x * sin + vector.y * cos;
return {
x: rx,
y: ry
};
},
transformPoint: function(p, t, ignoreOffset) {
if (ignoreOffset) {
@ -274,7 +281,7 @@ fabric.Collection = {
callback && callback.call(context, null, true);
img = img.onload = img.onerror = null;
};
if (url.indexOf("data") !== 0 && typeof crossOrigin !== "undefined") {
if (url.indexOf("data") !== 0 && crossOrigin) {
img.crossOrigin = crossOrigin;
}
img.src = url;
@ -382,15 +389,30 @@ fabric.Collection = {
return [ a[0] * b[0] + a[2] * b[1], a[1] * b[0] + a[3] * b[1], a[0] * b[2] + a[2] * b[3], a[1] * b[2] + a[3] * b[3], is2x2 ? 0 : a[0] * b[4] + a[2] * b[5] + a[4], is2x2 ? 0 : a[1] * b[4] + a[3] * b[5] + a[5] ];
},
qrDecompose: function(a) {
var angle = atan(a[0] / a[1]), denom = pow(a[0]) + pow(a[1]), scaleX = sqrt(denom), scaleY = (a[0] * a[3] - a[2] * a[1]) / scaleX, skewX = atan((a[0] * a[2] + a[1] * a[3]) / denom);
var angle = atan2(a[1], a[0]), denom = pow(a[0], 2) + pow(a[1], 2), scaleX = sqrt(denom), scaleY = (a[0] * a[3] - a[2] * a[1]) / scaleX, skewX = atan2(a[0] * a[2] + a[1] * a[3], denom);
return {
angle: angle / PiBy180,
scaleX: scaleX,
scaleY: scaleY,
skewX: skewX / PiBy180,
skewY: 0
skewY: 0,
translateX: a[4],
translateY: a[5]
};
},
customTransformMatrix: function(scaleX, scaleY, skewX) {
var skewMatrixX = [ 1, 0, abs(Math.tan(skewX * PiBy180)), 1 ], scaleMatrix = [ abs(scaleX), 0, 0, abs(scaleY) ];
return fabric.util.multiplyTransformMatrices(scaleMatrix, skewMatrixX, true);
},
resetObjectTransform: function(target) {
target.scaleX = 1;
target.scaleY = 1;
target.skewX = 0;
target.skewY = 0;
target.flipX = false;
target.flipY = false;
target.setAngle(0);
},
getFunctionBody: function(fn) {
return (String(fn).match(/function[^{]*\{([\s\S]*)\}/) || {})[1];
},
@ -1621,9 +1643,15 @@ if (typeof console !== "undefined") {
}
function _setStrokeFillOpacity(attributes) {
for (var attr in colorAttributes) {
if (!attributes[attr] || typeof attributes[colorAttributes[attr]] === "undefined") {
if (typeof attributes[colorAttributes[attr]] === "undefined") {
continue;
}
if (!attributes[attr]) {
if (!fabric.Object.prototype[attr]) {
continue;
}
attributes[attr] = fabric.Object.prototype[attr];
}
if (attributes[attr].indexOf("url(") === 0) {
continue;
}
@ -1634,11 +1662,13 @@ if (typeof console !== "undefined") {
}
fabric.parseTransformAttribute = function() {
function rotateMatrix(matrix, args) {
var angle = args[0];
var angle = args[0], x = args.length === 3 ? args[1] : 0, y = args.length === 3 ? args[2] : 0;
matrix[0] = Math.cos(angle);
matrix[1] = Math.sin(angle);
matrix[2] = -Math.sin(angle);
matrix[3] = Math.cos(angle);
matrix[4] = x - (matrix[0] * x + matrix[2] * y);
matrix[5] = y - (matrix[1] * x + matrix[3] * y);
}
function scaleMatrix(matrix, args) {
var multiplierX = args[0], multiplierY = args.length === 2 ? args[1] : args[0];
@ -2971,12 +3001,15 @@ fabric.Pattern = fabric.util.createClass({
return [ this.offsetX, this.offsetY, this.blur, this.color ].join("px ");
},
toSVG: function(object) {
var fBoxX = 40, fBoxY = 40;
var fBoxX = 40, fBoxY = 40, NUM_FRACTION_DIGITS = fabric.Object.NUM_FRACTION_DIGITS, offset = fabric.util.rotateVector({
x: this.offsetX,
y: this.offsetY
}, fabric.util.degreesToRadians(-object.angle)), BLUR_BOX = 20;
if (object.width && object.height) {
fBoxX = toFixed((Math.abs(this.offsetX) + this.blur) / object.width, 2) * 100 + 20;
fBoxY = toFixed((Math.abs(this.offsetY) + this.blur) / object.height, 2) * 100 + 20;
fBoxX = toFixed((Math.abs(offset.x) + this.blur) / object.width, NUM_FRACTION_DIGITS) * 100 + BLUR_BOX;
fBoxY = toFixed((Math.abs(offset.y) + this.blur) / object.height, NUM_FRACTION_DIGITS) * 100 + BLUR_BOX;
}
return '<filter id="SVGID_' + this.id + '" y="-' + fBoxY + '%" height="' + (100 + 2 * fBoxY) + '%" ' + 'x="-' + fBoxX + '%" width="' + (100 + 2 * fBoxX) + '%" ' + ">\n" + ' <feGaussianBlur in="SourceAlpha" stdDeviation="' + toFixed(this.blur ? this.blur / 2 : 0, 3) + '"></feGaussianBlur>\n' + ' <feOffset dx="' + this.offsetX + '" dy="' + this.offsetY + '" result="oBlur" ></feOffset>\n' + ' <feFlood flood-color="' + this.color + '"/>\n' + ' <feComposite in2="oBlur" operator="in" />\n' + " <feMerge>\n" + " <feMergeNode></feMergeNode>\n" + ' <feMergeNode in="SourceGraphic"></feMergeNode>\n' + " </feMerge>\n" + "</filter>\n";
return '<filter id="SVGID_' + this.id + '" y="-' + fBoxY + '%" height="' + (100 + 2 * fBoxY) + '%" ' + 'x="-' + fBoxX + '%" width="' + (100 + 2 * fBoxX) + '%" ' + ">\n" + ' <feGaussianBlur in="SourceAlpha" stdDeviation="' + toFixed(this.blur ? this.blur / 2 : 0, NUM_FRACTION_DIGITS) + '"></feGaussianBlur>\n' + ' <feOffset dx="' + toFixed(offset.x, NUM_FRACTION_DIGITS) + '" dy="' + toFixed(offset.y, NUM_FRACTION_DIGITS) + '" result="oBlur" ></feOffset>\n' + ' <feFlood flood-color="' + this.color + '"/>\n' + ' <feComposite in2="oBlur" operator="in" />\n' + " <feMerge>\n" + " <feMergeNode></feMergeNode>\n" + ' <feMergeNode in="SourceGraphic"></feMergeNode>\n' + " </feMerge>\n" + "</filter>\n";
},
toObject: function() {
if (this.includeDefaultValues) {
@ -2984,22 +3017,16 @@ fabric.Pattern = fabric.util.createClass({
color: this.color,
blur: this.blur,
offsetX: this.offsetX,
offsetY: this.offsetY
offsetY: this.offsetY,
affectStroke: this.affectStroke
};
}
var obj = {}, proto = fabric.Shadow.prototype;
if (this.color !== proto.color) {
obj.color = this.color;
}
if (this.blur !== proto.blur) {
obj.blur = this.blur;
}
if (this.offsetX !== proto.offsetX) {
obj.offsetX = this.offsetX;
}
if (this.offsetY !== proto.offsetY) {
obj.offsetY = this.offsetY;
}
[ "color", "blur", "offsetX", "offsetY", "affectStroke" ].forEach(function(prop) {
if (this[prop] !== proto[prop]) {
obj[prop] = this[prop];
}
}, this);
return obj;
}
});
@ -3012,7 +3039,7 @@ fabric.Pattern = fabric.util.createClass({
fabric.warn("fabric.StaticCanvas is already defined.");
return;
}
var extend = fabric.util.object.extend, getElementOffset = fabric.util.getElementOffset, removeFromArray = fabric.util.removeFromArray, CANVAS_INIT_ERROR = new Error("Could not initialize `canvas` element");
var extend = fabric.util.object.extend, getElementOffset = fabric.util.getElementOffset, removeFromArray = fabric.util.removeFromArray, toFixed = fabric.util.toFixed, CANVAS_INIT_ERROR = new Error("Could not initialize `canvas` element");
fabric.StaticCanvas = fabric.util.createClass({
initialize: function(el, options) {
options || (options = {});
@ -3192,6 +3219,7 @@ fabric.Pattern = fabric.util.createClass({
this._setCssDimension(prop, cssValue);
}
}
this._initRetinaScaling();
this._setImageSmoothing();
this.calcOffset();
if (!options.cssOnly) {
@ -3346,11 +3374,13 @@ fabric.Pattern = fabric.util.createClass({
if (this.clipTo) {
fabric.util.clipContext(this, canvasToDrawOn);
}
objsToRender = this._chooseObjectsToRender();
canvasToDrawOn.setTransform.apply(canvasToDrawOn, this.viewportTransform);
this._renderBackground(canvasToDrawOn);
canvasToDrawOn.save();
objsToRender = this._chooseObjectsToRender();
canvasToDrawOn.transform.apply(canvasToDrawOn, this.viewportTransform);
this._renderObjects(canvasToDrawOn, objsToRender);
this.preserveObjectStacking || this._renderObjects(canvasToDrawOn, [ this.getActiveGroup() ]);
canvasToDrawOn.restore();
if (!this.controlsAboveOverlay && this.interactive) {
this.drawControls(canvasToDrawOn);
}
@ -3362,7 +3392,7 @@ fabric.Pattern = fabric.util.createClass({
this.drawControls(canvasToDrawOn);
}
this.fire("after:render");
canvasToDrawOn.setTransform.apply(canvasToDrawOn, [ 1, 0, 0, 1, 0, 0 ]);
canvasToDrawOn.restore();
return this;
},
_renderObjects: function(ctx, objects) {
@ -3505,25 +3535,22 @@ fabric.Pattern = fabric.util.createClass({
return markup.join("");
},
_setSVGPreamble: function(markup, options) {
if (!options.suppressPreamble) {
markup.push('<?xml version="1.0" encoding="', options.encoding || "UTF-8", '" standalone="no" ?>\n', '<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" ', '"http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">\n');
if (options.suppressPreamble) {
return;
}
markup.push('<?xml version="1.0" encoding="', options.encoding || "UTF-8", '" standalone="no" ?>\n', '<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" ', '"http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">\n');
},
_setSVGHeader: function(markup, options) {
var width, height, vpt;
var width = options.width || this.width, height = options.height || this.height, vpt, viewBox = 'viewBox="0 0 ' + this.width + " " + this.height + '" ', NUM_FRACTION_DIGITS = fabric.Object.NUM_FRACTION_DIGITS;
if (options.viewBox) {
width = options.viewBox.width;
height = options.viewBox.height;
viewBox = 'viewBox="' + options.viewBox.x + " " + options.viewBox.y + " " + options.viewBox.width + " " + options.viewBox.height + '" ';
} else {
width = this.width;
height = this.height;
if (!this.svgViewportTransformation) {
if (this.svgViewportTransformation) {
vpt = this.viewportTransform;
width /= vpt[0];
height /= vpt[3];
viewBox = 'viewBox="' + toFixed(-vpt[4] / vpt[0], NUM_FRACTION_DIGITS) + " " + toFixed(-vpt[5] / vpt[3], NUM_FRACTION_DIGITS) + " " + toFixed(this.width / vpt[0], NUM_FRACTION_DIGITS) + " " + toFixed(this.height / vpt[3], NUM_FRACTION_DIGITS) + '" ';
}
}
markup.push("<svg ", 'xmlns="http://www.w3.org/2000/svg" ', 'xmlns:xlink="http://www.w3.org/1999/xlink" ', 'version="1.1" ', 'width="', width, '" ', 'height="', height, '" ', this.backgroundColor && !this.backgroundColor.toLive ? 'style="background-color: ' + this.backgroundColor + '" ' : null, options.viewBox ? 'viewBox="' + options.viewBox.x + " " + options.viewBox.y + " " + options.viewBox.width + " " + options.viewBox.height + '" ' : null, 'xml:space="preserve">\n', "<desc>Created with Fabric.js ", fabric.version, "</desc>\n", "<defs>", fabric.createSVGFontFacesMarkup(this.getObjects()), fabric.createSVGRefElementsMarkup(this), "</defs>\n");
markup.push("<svg ", 'xmlns="http://www.w3.org/2000/svg" ', 'xmlns:xlink="http://www.w3.org/1999/xlink" ', 'version="1.1" ', 'width="', width, '" ', 'height="', height, '" ', this.backgroundColor && !this.backgroundColor.toLive ? 'style="background-color: ' + this.backgroundColor + '" ' : null, viewBox, 'xml:space="preserve">\n', "<desc>Created with Fabric.js ", fabric.version, "</desc>\n", "<defs>", fabric.createSVGFontFacesMarkup(this.getObjects()), fabric.createSVGRefElementsMarkup(this), "</defs>\n");
},
_setSVGObjects: function(markup, reviver) {
for (var i = 0, objects = this.getObjects(), len = objects.length; i < len; i++) {
@ -4667,15 +4694,12 @@ fabric.PatternBrush = fabric.util.createClass(fabric.PencilBrush, {
return this;
},
drawControls: function(ctx) {
ctx.save();
ctx.setTransform.apply(ctx, [ 1, 0, 0, 1, 0, 0 ]);
var activeGroup = this.getActiveGroup();
if (activeGroup) {
activeGroup._renderControls(ctx);
} else {
this._drawObjectsControls(ctx);
}
ctx.restore();
},
_drawObjectsControls: function(ctx) {
for (var i = 0, len = this._objects.length; i < len; ++i) {
@ -5162,7 +5186,6 @@ fabric.PatternBrush = fabric.util.createClass(fabric.PencilBrush, {
var activeGroup = this.getActiveGroup();
if (activeGroup.contains(target)) {
activeGroup.removeWithUpdate(target);
this._resetObjectTransform(activeGroup);
target.set("active", false);
if (activeGroup.size() === 1) {
this.discardActiveGroup(e);
@ -5171,7 +5194,6 @@ fabric.PatternBrush = fabric.util.createClass(fabric.PencilBrush, {
}
} else {
activeGroup.addWithUpdate(target);
this._resetObjectTransform(activeGroup);
}
this.fire("selection:created", {
target: activeGroup,
@ -5738,22 +5760,18 @@ fabric.util.object.extend(fabric.StaticCanvas.prototype, {
if (!this.active || noTransform) {
return;
}
var vpt = this.getViewportTransform();
var vpt = this.getViewportTransform(), matrix = this.calcTransformMatrix(), options;
matrix = fabric.util.multiplyTransformMatrices(vpt, matrix);
options = fabric.util.qrDecompose(matrix);
ctx.save();
var center;
if (this.group) {
center = fabric.util.transformPoint(this.group.getCenterPoint(), vpt);
ctx.translate(center.x, center.y);
ctx.rotate(degreesToRadians(this.group.angle));
ctx.translate(options.translateX, options.translateY);
if (this.group && this.group === this.canvas.getActiveGroup()) {
ctx.rotate(degreesToRadians(options.angle));
this.drawBordersInGroup(ctx, options);
} else {
ctx.rotate(degreesToRadians(this.angle));
this.drawBorders(ctx);
}
center = fabric.util.transformPoint(this.getCenterPoint(), vpt, null != this.group);
if (this.group) {
center.x *= this.group.scaleX;
center.y *= this.group.scaleY;
}
ctx.translate(center.x, center.y);
ctx.rotate(degreesToRadians(this.angle));
this.drawBorders(ctx);
this.drawControls(ctx);
ctx.restore();
},
@ -6057,7 +6075,7 @@ fabric.util.object.extend(fabric.StaticCanvas.prototype, {
function getCoords(oCoords) {
return [ new fabric.Point(oCoords.tl.x, oCoords.tl.y), new fabric.Point(oCoords.tr.x, oCoords.tr.y), new fabric.Point(oCoords.br.x, oCoords.br.y), new fabric.Point(oCoords.bl.x, oCoords.bl.y) ];
}
var degreesToRadians = fabric.util.degreesToRadians;
var degreesToRadians = fabric.util.degreesToRadians, multiplyMatrices = fabric.util.multiplyTransformMatrices;
fabric.util.object.extend(fabric.Object.prototype, {
oCoords: null,
intersectsWithRect: function(pointTL, pointBR) {
@ -6196,9 +6214,23 @@ fabric.util.object.extend(fabric.StaticCanvas.prototype, {
this._setCornerCoords && this._setCornerCoords();
return this;
},
_calcDimensionsTransformMatrix: function(skewX, skewY) {
var skewMatrixX = [ 1, 0, Math.tan(degreesToRadians(skewX)), 1, 0, 0 ], skewMatrixY = [ 1, Math.tan(degreesToRadians(skewY)), 0, 1, 0, 0 ], scaleMatrix = [ this.scaleX, 0, 0, this.scaleY, 0, 0 ], m = fabric.util.multiplyTransformMatrices(scaleMatrix, skewMatrixX, true);
return fabric.util.multiplyTransformMatrices(m, skewMatrixY, true);
_calcRotateMatrix: function() {
if (this.angle) {
var theta = degreesToRadians(this.angle), cos = Math.cos(theta), sin = Math.sin(theta);
return [ cos, sin, -sin, cos, 0, 0 ];
}
return [ 1, 0, 0, 1, 0, 0 ];
},
calcTransformMatrix: function() {
var center = this.getCenterPoint(), translateMatrix = [ 1, 0, 0, 1, center.x, center.y ], rotateMatrix = this._calcRotateMatrix(), dimensionMatrix = this._calcDimensionsTransformMatrix(this.skewX, this.skewY, true), matrix = this.group ? this.group.calcTransformMatrix() : [ 1, 0, 0, 1, 0, 0 ];
matrix = multiplyMatrices(matrix, translateMatrix);
matrix = multiplyMatrices(matrix, rotateMatrix);
matrix = multiplyMatrices(matrix, dimensionMatrix);
return matrix;
},
_calcDimensionsTransformMatrix: function(skewX, skewY, flipping) {
var skewMatrixX = [ 1, 0, Math.tan(degreesToRadians(skewX)), 1 ], skewMatrixY = [ 1, Math.tan(degreesToRadians(skewY)), 0, 1 ], scaleX = this.scaleX * (flipping && this.flipX ? -1 : 1), scaleY = this.scaleY * (flipping && this.flipY ? -1 : 1), scaleMatrix = [ scaleX, 0, 0, scaleY ], m = multiplyMatrices(scaleMatrix, skewMatrixX, true);
return multiplyMatrices(m, skewMatrixY, true);
}
});
})();
@ -6258,7 +6290,7 @@ fabric.util.object.extend(fabric.Object.prototype, {
if (this.group && this.group.type === "path-group") {
return "";
}
var toFixed = fabric.util.toFixed, angle = this.getAngle(), skewX = this.getSkewX() % 360, skewY = this.getSkewY() % 360, vpt = !this.canvas || this.canvas.svgViewportTransformation ? this.getViewportTransform() : [ 1, 0, 0, 1, 0, 0 ], center = fabric.util.transformPoint(this.getCenterPoint(), vpt), NUM_FRACTION_DIGITS = fabric.Object.NUM_FRACTION_DIGITS, translatePart = this.type === "path-group" ? "" : "translate(" + toFixed(center.x, NUM_FRACTION_DIGITS) + " " + toFixed(center.y, NUM_FRACTION_DIGITS) + ")", anglePart = angle !== 0 ? " rotate(" + toFixed(angle, NUM_FRACTION_DIGITS) + ")" : "", scalePart = this.scaleX === 1 && this.scaleY === 1 && vpt[0] === 1 && vpt[3] === 1 ? "" : " scale(" + toFixed(this.scaleX * vpt[0], NUM_FRACTION_DIGITS) + " " + toFixed(this.scaleY * vpt[3], NUM_FRACTION_DIGITS) + ")", skewXPart = skewX !== 0 ? " skewX(" + toFixed(skewX, NUM_FRACTION_DIGITS) + ")" : "", skewYPart = skewY !== 0 ? " skewY(" + toFixed(skewY, NUM_FRACTION_DIGITS) + ")" : "", addTranslateX = this.type === "path-group" ? this.width * vpt[0] : 0, flipXPart = this.flipX ? " matrix(-1 0 0 1 " + addTranslateX + " 0) " : "", addTranslateY = this.type === "path-group" ? this.height * vpt[3] : 0, flipYPart = this.flipY ? " matrix(1 0 0 -1 0 " + addTranslateY + ")" : "";
var toFixed = fabric.util.toFixed, angle = this.getAngle(), skewX = this.getSkewX() % 360, skewY = this.getSkewY() % 360, center = this.getCenterPoint(), NUM_FRACTION_DIGITS = fabric.Object.NUM_FRACTION_DIGITS, translatePart = this.type === "path-group" ? "" : "translate(" + toFixed(center.x, NUM_FRACTION_DIGITS) + " " + toFixed(center.y, NUM_FRACTION_DIGITS) + ")", anglePart = angle !== 0 ? " rotate(" + toFixed(angle, NUM_FRACTION_DIGITS) + ")" : "", scalePart = this.scaleX === 1 && this.scaleY === 1 ? "" : " scale(" + toFixed(this.scaleX, NUM_FRACTION_DIGITS) + " " + toFixed(this.scaleY, NUM_FRACTION_DIGITS) + ")", skewXPart = skewX !== 0 ? " skewX(" + toFixed(skewX, NUM_FRACTION_DIGITS) + ")" : "", skewYPart = skewY !== 0 ? " skewY(" + toFixed(skewY, NUM_FRACTION_DIGITS) + ")" : "", addTranslateX = this.type === "path-group" ? this.width : 0, flipXPart = this.flipX ? " matrix(-1 0 0 1 " + addTranslateX + " 0) " : "", addTranslateY = this.type === "path-group" ? this.height : 0, flipYPart = this.flipY ? " matrix(1 0 0 -1 0 " + addTranslateY + ")" : "";
return [ translatePart, anglePart, scalePart, flipXPart, flipYPart, skewXPart, skewYPart ].join("");
},
getSvgTransformMatrix: function() {
@ -6398,7 +6430,7 @@ fabric.util.object.extend(fabric.Object.prototype, {
}, {
x: dimX,
y: dimY
} ], i, transformMatrix = this._calcDimensionsTransformMatrix(skewX, skewY), bbox;
} ], i, transformMatrix = this._calcDimensionsTransformMatrix(skewX, skewY, false), bbox;
for (i = 0; i < points.length; i++) {
points[i] = fabric.util.transformPoint(points[i], transformMatrix);
}
@ -6418,16 +6450,12 @@ fabric.util.object.extend(fabric.Object.prototype, {
if (!this.hasBorders) {
return this;
}
var wh = this._calculateCurrentDimensions(), strokeWidth = 1 / this.borderScaleFactor, width = wh.x + strokeWidth, height = wh.y + strokeWidth;
ctx.save();
ctx.globalAlpha = this.isMoving ? this.borderOpacityWhenMoving : 1;
ctx.strokeStyle = this.borderColor;
ctx.lineWidth = 1 / this.borderScaleFactor;
var wh = this._calculateCurrentDimensions(), width = wh.x, height = wh.y;
if (this.group) {
width = width * this.group.scaleX;
height = height * this.group.scaleY;
}
ctx.strokeRect(~~-(width / 2) - .5, ~~-(height / 2) - .5, ~~width + 1, ~~height + 1);
ctx.lineWidth = strokeWidth;
ctx.strokeRect(-width / 2, -height / 2, width, height);
if (this.hasRotatingPoint && this.isControlVisible("mtr") && !this.get("lockRotation") && this.hasControls) {
var rotateHeight = -height / 2;
ctx.beginPath();
@ -6439,11 +6467,24 @@ fabric.util.object.extend(fabric.Object.prototype, {
ctx.restore();
return this;
},
drawBordersInGroup: function(ctx, options) {
if (!this.hasBorders) {
return this;
}
var p = this._getNonTransformedDimensions(), matrix = fabric.util.customTransformMatrix(options.scaleX, options.scaleY, options.skewX), wh = fabric.util.transformPoint(p, matrix), strokeWidth = 1 / this.borderScaleFactor, width = wh.x + strokeWidth + 2 * this.padding, height = wh.y + strokeWidth + 2 * this.padding;
ctx.save();
ctx.globalAlpha = this.isMoving ? this.borderOpacityWhenMoving : 1;
ctx.strokeStyle = this.borderColor;
ctx.lineWidth = strokeWidth;
ctx.strokeRect(-width / 2, -height / 2, width, height);
ctx.restore();
return this;
},
drawControls: function(ctx) {
if (!this.hasControls) {
return this;
}
var wh = this._calculateCurrentDimensions(), width = wh.x, height = wh.y, scaleOffset = this.cornerSize / 2, left = -(width / 2) - scaleOffset, top = -(height / 2) - scaleOffset, methodName = this.transparentCorners ? "strokeRect" : "fillRect";
var wh = this._calculateCurrentDimensions(), width = wh.x, height = wh.y, scaleOffset = this.cornerSize, left = -(width + scaleOffset) / 2, top = -(height + scaleOffset) / 2, methodName = this.transparentCorners ? "strokeRect" : "fillRect";
ctx.save();
ctx.lineWidth = 1;
ctx.globalAlpha = this.isMoving ? this.borderOpacityWhenMoving : 1;
@ -7996,6 +8037,7 @@ fabric.util.object.extend(fabric.Object.prototype, {
},
addWithUpdate: function(object) {
this._restoreObjectsState();
fabric.util.resetObjectTransform(this);
if (object) {
this._objects.push(object);
object.group = this;
@ -8011,8 +8053,8 @@ fabric.util.object.extend(fabric.Object.prototype, {
object.group = this;
},
removeWithUpdate: function(object) {
this._moveFlippedObject(object);
this._restoreObjectsState();
fabric.util.resetObjectTransform(this);
this.forEachObject(this._setObjectActive, this);
this.remove(object);
this._calcBounds();
@ -8029,7 +8071,8 @@ fabric.util.object.extend(fabric.Object.prototype, {
},
delegatedProperties: {
fill: true,
opacity: true,
stroke: true,
strokeWidth: true,
fontFamily: true,
fontWeight: true,
fontSize: true,
@ -8094,69 +8137,27 @@ fabric.util.object.extend(fabric.Object.prototype, {
return this;
},
realizeTransform: function(object) {
this._moveFlippedObject(object);
this._setObjectPosition(object);
var matrix = object.calcTransformMatrix(), options = fabric.util.qrDecompose(matrix), center = new fabric.Point(options.translateX, options.translateY);
object.scaleX = options.scaleX;
object.scaleY = options.scaleY;
object.skewX = options.skewX;
object.skewY = options.skewY;
object.angle = options.angle;
object.flipX = false;
object.flipY = false;
object.setPositionByOrigin(center, "center", "center");
return object;
},
_moveFlippedObject: function(object) {
var oldOriginX = object.get("originX"), oldOriginY = object.get("originY"), center = object.getCenterPoint();
object.set({
originX: "center",
originY: "center",
left: center.x,
top: center.y
});
this._toggleFlipping(object);
var newOrigin = object.getPointByOrigin(oldOriginX, oldOriginY);
object.set({
originX: oldOriginX,
originY: oldOriginY,
left: newOrigin.x,
top: newOrigin.y
});
return this;
},
_toggleFlipping: function(object) {
if (this.flipX) {
object.toggle("flipX");
object.set("left", -object.get("left"));
object.setAngle(-object.getAngle());
}
if (this.flipY) {
object.toggle("flipY");
object.set("top", -object.get("top"));
object.setAngle(-object.getAngle());
}
},
_restoreObjectState: function(object) {
this._setObjectPosition(object);
this.realizeTransform(object);
object.setCoords();
object.hasControls = object.__origHasControls;
delete object.__origHasControls;
object.set("active", false);
object.setCoords();
delete object.group;
return this;
},
_setObjectPosition: function(object) {
var center = this.getCenterPoint(), rotated = this._getRotatedLeftTop(object);
object.set({
angle: object.getAngle() + this.getAngle(),
left: center.x + rotated.left,
top: center.y + rotated.top,
scaleX: object.get("scaleX") * this.get("scaleX"),
scaleY: object.get("scaleY") * this.get("scaleY")
});
},
_getRotatedLeftTop: function(object) {
var groupAngle = this.getAngle() * (Math.PI / 180);
return {
left: -Math.sin(groupAngle) * object.getTop() * this.get("scaleY") + Math.cos(groupAngle) * object.getLeft() * this.get("scaleX"),
top: Math.cos(groupAngle) * object.getTop() * this.get("scaleY") + Math.sin(groupAngle) * object.getLeft() * this.get("scaleX")
};
},
destroy: function() {
this._objects.forEach(this._moveFlippedObject, this);
return this._restoreObjectsState();
},
saveCoords: function() {
@ -8263,6 +8264,7 @@ fabric.util.object.extend(fabric.Object.prototype, {
alignX: "none",
alignY: "none",
meetOrSlice: "meet",
strokeWidth: 0,
_lastScaleX: 1,
_lastScaleY: 1,
initialize: function(element, options) {
@ -8644,24 +8646,25 @@ fabric.Image.filters.BaseFilter = fabric.util.createClass({
options = options || {};
this.opaque = options.opaque;
this.matrix = options.matrix || [ 0, 0, 0, 0, 1, 0, 0, 0, 0 ];
var canvasEl = fabric.util.createCanvasElement();
this.tmpCtx = canvasEl.getContext("2d");
},
_createImageData: function(w, h) {
return this.tmpCtx.createImageData(w, h);
},
applyTo: function(canvasEl) {
var weights = this.matrix, context = canvasEl.getContext("2d"), pixels = context.getImageData(0, 0, canvasEl.width, canvasEl.height), side = Math.round(Math.sqrt(weights.length)), halfSide = Math.floor(side / 2), src = pixels.data, sw = pixels.width, sh = pixels.height, w = sw, h = sh, output = this._createImageData(w, h), dst = output.data, alphaFac = this.opaque ? 1 : 0;
for (var y = 0; y < h; y++) {
for (var x = 0; x < w; x++) {
var sy = y, sx = x, dstOff = (y * w + x) * 4, r = 0, g = 0, b = 0, a = 0;
var weights = this.matrix, context = canvasEl.getContext("2d"), pixels = context.getImageData(0, 0, canvasEl.width, canvasEl.height), side = Math.round(Math.sqrt(weights.length)), halfSide = Math.floor(side / 2), src = pixels.data, sw = pixels.width, sh = pixels.height, output = context.createImageData(sw, sh), dst = output.data, alphaFac = this.opaque ? 1 : 0, r, g, b, a, dstOff, scx, scy, srcOff, wt;
for (var y = 0; y < sh; y++) {
for (var x = 0; x < sw; x++) {
dstOff = (y * sw + x) * 4;
r = 0;
g = 0;
b = 0;
a = 0;
for (var cy = 0; cy < side; cy++) {
for (var cx = 0; cx < side; cx++) {
var scy = sy + cy - halfSide, scx = sx + cx - halfSide;
scy = y + cy - halfSide;
scx = x + cx - halfSide;
if (scy < 0 || scy > sh || scx < 0 || scx > sw) {
continue;
}
var srcOff = (scy * sw + scx) * 4, wt = weights[cy * side + cx];
srcOff = (scy * sw + scx) * 4;
wt = weights[cy * side + cx];
r += src[srcOff] * wt;
g += src[srcOff + 1] * wt;
b += src[srcOff + 2] * wt;
@ -9448,14 +9451,14 @@ fabric.Image.filters.BaseFilter = fabric.util.createClass({
this._renderChars(method, ctx, line, left, top, lineIndex);
return;
}
var words = line.split(/\s+/), wordsWidth = this._getWidthOfWords(ctx, line, lineIndex), widthDiff = this.width - wordsWidth, numSpaces = words.length - 1, spaceWidth = numSpaces > 0 ? widthDiff / numSpaces : 0, leftOffset = 0, charOffset = 0, word;
var words = line.split(/\s+/), charOffset = 0, wordsWidth = this._getWidthOfWords(ctx, line, lineIndex, 0), widthDiff = this.width - wordsWidth, numSpaces = words.length - 1, spaceWidth = numSpaces > 0 ? widthDiff / numSpaces : 0, leftOffset = 0, word;
for (var i = 0, len = words.length; i < len; i++) {
while (line[charOffset] === " " && charOffset < line.length) {
charOffset++;
}
word = words[i];
this._renderChars(method, ctx, word, left + leftOffset, top, lineIndex, charOffset);
leftOffset += ctx.measureText(word).width + spaceWidth;
leftOffset += this._getWidthOfWords(ctx, word, lineIndex, charOffset) + spaceWidth;
charOffset += word.length;
}
},
@ -9525,7 +9528,7 @@ fabric.Image.filters.BaseFilter = fabric.util.createClass({
ctx.fillStyle = this.textBackgroundColor;
for (var i = 0, len = this._textLines.length; i < len; i++) {
if (this._textLines[i] !== "") {
lineWidth = this._getLineWidth(ctx, i);
lineWidth = this.textAlign === "justify" ? this.width : this._getLineWidth(ctx, i);
lineLeftOffset = this._getLineLeftOffset(lineWidth);
ctx.fillRect(this._getLeftOffset() + lineLeftOffset, this._getTopOffset() + lineTopOffset, lineWidth, this.fontSize * this._fontSizeMult);
}
@ -9567,7 +9570,7 @@ fabric.Image.filters.BaseFilter = fabric.util.createClass({
if (line === "") {
width = 0;
} else if (this.textAlign === "justify" && this._cacheLinesWidth) {
wordCount = line.split(" ");
wordCount = line.split(/\s+/);
if (wordCount.length > 1) {
width = this.width;
} else {
@ -9666,7 +9669,7 @@ fabric.Image.filters.BaseFilter = fabric.util.createClass({
};
},
_wrapSVGTextAndBg: function(markup, textAndBg) {
markup.push(' <g transform="', this.getSvgTransform(), this.getSvgTransformMatrix(), '">\n', textAndBg.textBgRects.join(""), " <text ", this.fontFamily ? 'font-family="' + this.fontFamily.replace(/"/g, "'") + '" ' : "", this.fontSize ? 'font-size="' + this.fontSize + '" ' : "", this.fontStyle ? 'font-style="' + this.fontStyle + '" ' : "", this.fontWeight ? 'font-weight="' + this.fontWeight + '" ' : "", this.textDecoration ? 'text-decoration="' + this.textDecoration + '" ' : "", 'style="', this.getSvgStyles(), '" >', textAndBg.textSpans.join(""), "</text>\n", " </g>\n");
markup.push(' <g transform="', this.getSvgTransform(), this.getSvgTransformMatrix(), '">\n', textAndBg.textBgRects.join(""), " <text ", this.fontFamily ? 'font-family="' + this.fontFamily.replace(/"/g, "'") + '" ' : "", this.fontSize ? 'font-size="' + this.fontSize + '" ' : "", this.fontStyle ? 'font-style="' + this.fontStyle + '" ' : "", this.fontWeight ? 'font-weight="' + this.fontWeight + '" ' : "", this.textDecoration ? 'text-decoration="' + this.textDecoration + '" ' : "", 'style="', this.getSvgStyles(), '" >\n', textAndBg.textSpans.join(""), " </text>\n", " </g>\n");
},
_getSVGTextAndBg: function(textTopOffset, textLeftOffset) {
var textSpans = [], textBgRects = [], height = 0;
@ -9685,7 +9688,22 @@ fabric.Image.filters.BaseFilter = fabric.util.createClass({
},
_setSVGTextLineText: function(i, textSpans, height, textLeftOffset, textTopOffset) {
var yPos = this.fontSize * (this._fontSizeMult - this._fontSizeFraction) - textTopOffset + height - this.height / 2;
textSpans.push('<tspan x="', toFixed(textLeftOffset + this._getLineLeftOffset(this._getLineWidth(this.ctx, i)), NUM_FRACTION_DIGITS), '" ', 'y="', toFixed(yPos, NUM_FRACTION_DIGITS), '" ', this._getFillAttributes(this.fill), ">", fabric.util.string.escapeXml(this._textLines[i]), "</tspan>");
if (this.textAlign === "justify") {
this._setSVGTextLineJustifed(i, textSpans, yPos, textLeftOffset);
return;
}
textSpans.push(' <tspan x="', toFixed(textLeftOffset + this._getLineLeftOffset(this._getLineWidth(this.ctx, i)), NUM_FRACTION_DIGITS), '" ', 'y="', toFixed(yPos, NUM_FRACTION_DIGITS), '" ', this._getFillAttributes(this.fill), ">", fabric.util.string.escapeXml(this._textLines[i]), "</tspan>\n");
},
_setSVGTextLineJustifed: function(i, textSpans, yPos, textLeftOffset) {
var ctx = fabric.util.createCanvasElement().getContext("2d");
this._setTextStyles(ctx);
var line = this._textLines[i], words = line.split(/\s+/), wordsWidth = this._getWidthOfWords(ctx, line), widthDiff = this.width - wordsWidth, numSpaces = words.length - 1, spaceWidth = numSpaces > 0 ? widthDiff / numSpaces : 0, word, attributes = this._getFillAttributes(this.fill);
textLeftOffset += this._getLineLeftOffset(this._getLineWidth(ctx, i));
for (var i = 0, len = words.length; i < len; i++) {
word = words[i];
textSpans.push(' <tspan x="', toFixed(textLeftOffset, NUM_FRACTION_DIGITS), '" ', 'y="', toFixed(yPos, NUM_FRACTION_DIGITS), '" ', attributes, ">", fabric.util.string.escapeXml(word), "</tspan>\n");
textLeftOffset += this._getWidthOfWords(ctx, word) + spaceWidth;
}
},
_setSVGTextLineBg: function(textBgRects, i, textLeftOffset, textTopOffset, height) {
textBgRects.push(" <rect ", this._getFillAttributes(this.textBackgroundColor), ' x="', toFixed(textLeftOffset + this._getLineLeftOffset(this._getLineWidth(this.ctx, i)), NUM_FRACTION_DIGITS), '" y="', toFixed(height - this.height / 2, NUM_FRACTION_DIGITS), '" width="', toFixed(this._getLineWidth(this.ctx, i), NUM_FRACTION_DIGITS), '" height="', toFixed(this._getHeightOfLine(this.ctx, i) / this.lineHeight, NUM_FRACTION_DIGITS), '"></rect>\n');
@ -9735,7 +9753,18 @@ fabric.Image.filters.BaseFilter = fabric.util.createClass({
if (!options.originX) {
options.originX = "left";
}
var textContent = element.textContent.replace(/^\s+|\s+$|\n+/g, "").replace(/\s+/g, " "), text = new fabric.Text(textContent, options), offX = 0;
var textContent = "";
if (!("textContent" in element)) {
if ("firstChild" in element && element.firstChild !== null) {
if ("data" in element.firstChild && element.firstChild.data !== null) {
textContent = element.firstChild.data;
}
}
} else {
textContent = element.textContent;
}
textContent = textContent.replace(/^\s+|\s+$|\n+/g, "").replace(/\s+/g, " ");
var text = new fabric.Text(textContent, options), offX = 0;
if (text.originX === "left") {
offX = text.getWidth() / 2;
}
@ -10208,16 +10237,16 @@ fabric.Image.filters.BaseFilter = fabric.util.createClass({
if (this.__widthOfSpace[lineIndex]) {
return this.__widthOfSpace[lineIndex];
}
var line = this._textLines[lineIndex], wordsWidth = this._getWidthOfWords(ctx, line, lineIndex), widthDiff = this.width - wordsWidth, numSpaces = line.length - line.replace(this._reSpacesAndTabs, "").length, width = widthDiff / numSpaces;
var line = this._textLines[lineIndex], wordsWidth = this._getWidthOfWords(ctx, line, lineIndex, 0), widthDiff = this.width - wordsWidth, numSpaces = line.length - line.replace(this._reSpacesAndTabs, "").length, width = widthDiff / numSpaces;
this.__widthOfSpace[lineIndex] = width;
return width;
},
_getWidthOfWords: function(ctx, line, lineIndex) {
_getWidthOfWords: function(ctx, line, lineIndex, charOffset) {
var width = 0;
for (var charIndex = 0; charIndex < line.length; charIndex++) {
var _char = line[charIndex];
if (!_char.match(/\s/)) {
width += this._getWidthOfChar(ctx, _char, lineIndex, charIndex);
width += this._getWidthOfChar(ctx, _char, lineIndex, charIndex + charOffset);
}
}
return width;
@ -10785,6 +10814,9 @@ fabric.util.object.extend(fabric.IText.prototype, {
},
initMousedownHandler: function() {
this.on("mousedown", function(options) {
if (!this.editable) {
return;
}
var pointer = this.canvas.getPointer(options.e);
this.__mousedownX = pointer.x;
this.__mousedownY = pointer.y;
@ -10808,7 +10840,7 @@ fabric.util.object.extend(fabric.IText.prototype, {
initMouseupHandler: function() {
this.on("mouseup", function(options) {
this.__isMousedown = false;
if (this._isObjectMoved(options.e)) {
if (!this.editable || this._isObjectMoved(options.e)) {
return;
}
if (this.__lastSelected && !this.__corner) {

View file

@ -98,8 +98,8 @@
for (var y = 0; y < sh; y++) {
for (var x = 0; x < sw; x++) {
dstOff = (y * sw + x) * 4;
// calculate the weighed sum of the source image pixels that
// fall under the convolution matrix
// calculate the weighed sum of the source image pixels that
// fall under the convolution matrix
r = 0; g = 0; b = 0; a = 0;
for (var cy = 0; cy < side; cy++) {

View file

@ -112,8 +112,10 @@
*/
toSVG: function(object) {
var fBoxX = 40, fBoxY = 40, NUM_FRACTION_DIGITS = fabric.Object.NUM_FRACTION_DIGITS,
offset = fabric.util.rotateVector({x: this.offsetX, y: this.offsetY},
fabric.util.degreesToRadians(-object.angle)), BLUR_BOX = 20;
offset = fabric.util.rotateVector(
{ x: this.offsetX, y: this.offsetY },
fabric.util.degreesToRadians(-object.angle)),
BLUR_BOX = 20;
if (object.width && object.height) {
//http://www.w3.org/TR/SVG/filters.html#FilterEffectsRegion

View file

@ -949,16 +949,21 @@
_setSVGTextLineJustifed: function(i, textSpans, yPos, textLeftOffset) {
var ctx = fabric.util.createCanvasElement().getContext('2d');
this._setTextStyles(ctx);
var line = this._textLines[i],
words = line.split(/\s+/),
wordsWidth = this._getWidthOfWords(ctx, line),
widthDiff = this.width - wordsWidth,
numSpaces = words.length - 1,
spaceWidth = numSpaces > 0 ? widthDiff / numSpaces : 0,
word, attributes = this._getFillAttributes(this.fill);
textLeftOffset += this._getLineLeftOffset(this._getLineWidth(ctx, i))
for (var i = 0, len = words.length; i < len; i++) {
word, attributes = this._getFillAttributes(this.fill),
len;
textLeftOffset += this._getLineLeftOffset(this._getLineWidth(ctx, i));
for (i = 0, len = words.length; i < len; i++) {
word = words[i];
textSpans.push(
'\t\t\t<tspan x="',
@ -974,7 +979,6 @@
);
textLeftOffset += this._getWidthOfWords(ctx, word) + spaceWidth;
}
},
_setSVGTextLineBg: function(textBgRects, i, textLeftOffset, textTopOffset, height) {
@ -1102,7 +1106,7 @@
var textContent = '';
// The XML is not properly parsed in IE9 so a workaround to get
// The XML is not properly parsed in IE9 so a workaround to get
// textContent is through firstChild.data. Another workaround would be
// to convert XML loaded from a file to be converted using DOMParser (same way loadSVGFromString() does)
if (!('textContent' in element)) {
@ -1111,12 +1115,13 @@
textContent = element.firstChild.data;
}
}
} else {
}
else {
textContent = element.textContent;
}
textContent = textContent.replace(/^\s+|\s+$|\n+/g, '').replace(/\s+/g, ' ');
var text = new fabric.Text(textContent, options),
/*
Adjust positioning:

View file

@ -1184,7 +1184,7 @@
* @param {Number} [options.viewBox.width] Width of viewbox
* @param {Number} [options.viewBox.height] Height of viewbox
* @param {String} [options.encoding=UTF-8] Encoding of SVG output
* @param {String} [options.width] desired width of svg with or without units
* @param {String} [options.width] desired width of svg with or without units
* @param {String} [options.height] desired height of svg with or without units
* @param {Function} [reviver] Method for further parsing of svg elements, called after each fabric object converted into svg representation.
* @return {String} SVG string

View file

@ -2,7 +2,6 @@
var sqrt = Math.sqrt,
atan2 = Math.atan2,
atan = Math.atan,
pow = Math.pow,
abs = Math.abs,
PiBy180 = Math.PI / 180;
@ -82,9 +81,7 @@
* Rotates `vector` with `radians`
* @static
* @memberOf fabric.util
* @param {Object} vector The vector to rotate
* @param {Object.x} x coordinate of vector
* @param {Object.y} y coordinate of vector
* @param {Object} vector The vector to rotate (x and y)
* @param {Number} radians The radians of the angle for the rotation
* @return {Object} The new rotated point
*/
@ -94,7 +91,7 @@
rx = vector.x * cos - vector.y * sin,
ry = vector.x * sin + vector.y * cos;
return {
x: rx,
x: rx,
y: ry
};
},