Add support for skew objects.

This commit is contained in:
Andrea Bogazzi 2015-09-02 21:28:57 +02:00
parent 7a8c69e0ff
commit cda0611326
24 changed files with 367 additions and 98 deletions

View file

@ -213,17 +213,19 @@
* @private
* @param {Event} e Event object fired on mousemove
*/
_resetCurrentTransform: function(e) {
_resetCurrentTransform: function() {
var t = this._currentTransform;
t.target.set({
scaleX: t.original.scaleX,
scaleY: t.original.scaleY,
skewX: t.original.skewX,
skewY: t.original.skewY,
left: t.original.left,
top: t.original.top
});
if (this._shouldCenterTransform(e, t.target)) {
if (this._shouldCenterTransform(t.target)) {
if (t.action === 'rotate') {
this._setOriginToCenter(t.target);
}
@ -348,10 +350,9 @@
/**
* @private
* @param {Event} e Event object
* @param {fabric.Object} target
*/
_shouldCenterTransform: function (e, target) {
_shouldCenterTransform: function (target) {
if (!target) {
return;
}
@ -366,7 +367,7 @@
centerTransform = this.centeredRotation || target.centeredRotation;
}
return centerTransform ? !e.altKey : e.altKey;
return centerTransform ? !t.altKey : t.altKey;
},
/**
@ -398,18 +399,23 @@
/**
* @private
*/
_getActionFromCorner: function(target, corner) {
var action = 'drag';
if (corner) {
action = (corner === 'ml' || corner === 'mr')
? 'scaleX'
: (corner === 'mt' || corner === 'mb')
? 'scaleY'
: corner === 'mtr'
? 'rotate'
: 'scale';
_getActionFromCorner: function(target, corner, e) {
if (!corner) {
return 'drag';
}
switch (corner) {
case 'mtr':
return 'rotate';
case 'ml':
case 'mr':
return e.shiftKey ? 'skewY' : 'scaleX';
case 'mt':
case 'mb':
return e.shiftKey ? 'skewX' : 'scaleY';
default:
return 'scale';
}
return action;
},
/**
@ -424,26 +430,33 @@
var pointer = this.getPointer(e),
corner = target._findTargetCorner(this.getPointer(e, true)),
action = this._getActionFromCorner(target, corner),
action = this._getActionFromCorner(target, corner, e),
origin = this._getOriginFromCorner(target, corner);
this._currentTransform = {
target: target,
action: action,
corner: corner,
scaleX: target.scaleX,
scaleY: target.scaleY,
skewX: target.skewX,
skewY: target.skewY,
offsetX: pointer.x - target.left,
offsetY: pointer.y - target.top,
originX: origin.x,
originY: origin.y,
ex: pointer.x,
ey: pointer.y,
lastX: pointer.x,
lastY: pointer.y,
left: target.left,
top: target.top,
theta: degreesToRadians(target.angle),
width: target.width * target.scaleX,
mouseXSign: 1,
mouseYSign: 1
mouseYSign: 1,
shiftKey: e.shiftKey,
altKey: e.altKey
};
this._currentTransform.original = {
@ -451,11 +464,13 @@
top: target.top,
scaleX: target.scaleX,
scaleY: target.scaleY,
skewX: target.skewX,
skewY: target.skewY,
originX: origin.x,
originY: origin.y
};
this._resetCurrentTransform(e);
this._resetCurrentTransform();
},
/**
@ -475,6 +490,114 @@
}
},
/**
* Check if we are increasing a positive skew or lower it,
* checking mouse direction and pressed corner.
* @private
*/
_changeSkewTransformOrigin: function(mouseMove, t, by) {
var property = 'originX', origins = { 0: 'center' },
skew = t.target.skewX, originA = 'left', originB = 'right',
corner = t.corner === 'mt' || t.corner === 'ml' ? 1 : -1,
flipSign = 1;
mouseMove = mouseMove > 0 ? 1 : -1;
if (by === 'y') {
skew = t.target.skewY;
originA = 'top';
originB = 'bottom';
property = 'originY';
}
origins[-1] = originA;
origins[1] = originB;
t.target.flipX && (flipSign *= -1);
t.target.flipY && (flipSign *= -1);
if (skew === 0) {
t.skewSign = -corner * mouseMove * flipSign;
t[property] = origins[-mouseMove];
}
else {
skew = skew > 0 ? 1 : -1;
t.skewSign = skew;
t[property] = origins[skew * corner * flipSign];
}
},
/**
* Skew object by mouse events
* @private
* @param {Number} x pointer's x coordinate
* @param {Number} y pointer's y coordinate
* @param {String} by Either 'x' or 'y'
*/
_skewObject: function (x, y, by) {
var t = this._currentTransform,
target = t.target,
lockSkewingX = target.get('lockSkewingX'),
lockSkewingY = target.get('lockSkewingY');
if ((lockSkewingX && by === 'x') || (lockSkewingY && by === 'y')) {
return;
}
// Get the constraint point
var center = target.getCenterPoint(),
actualMouseByCenter = target.toLocalPoint(new fabric.Point(x, y), 'center', 'center')[by],
lastMouseByCenter = target.toLocalPoint(new fabric.Point(t.lastX, t.lastY), 'center', 'center')[by],
actualMouseByOrigin, constraintPosition, dim = target._getTransformedDimensions();
this._changeSkewTransformOrigin(actualMouseByCenter - lastMouseByCenter, t, by);
actualMouseByOrigin = target.toLocalPoint(new fabric.Point(x, y), t.originX, t.originY)[by],
constraintPosition = target.translateToOriginPoint(center, t.originX, t.originY);
// Actually skew the object
this._setObjectSkew(actualMouseByOrigin, t, by, dim);
t.lastX = x;
t.lastY = y;
// Make sure the constraints apply
target.setPositionByOrigin(constraintPosition, t.originX, t.originY);
},
_setObjectSkew: function(localMouse, transform, by, _dim) {
var target = transform.target, newValue,
skewSign = transform.skewSign, newDim, dimNoSkew,
otherBy, _otherBy, _by, newDimMouse, skewX, skewY;
if (by === 'x') {
otherBy = 'y';
_otherBy = 'Y';
_by = 'X';
skewX = 0;
skewY = target.skewY;
}
else {
otherBy = 'x';
_otherBy = 'X';
_by = 'Y';
skewX = target.skewX;
skewY = 0;
}
dimNoSkew = target._getTransformedDimensions(skewX, skewY);
newDimMouse = 2 * Math.abs(localMouse) - dimNoSkew[by];
if (newDimMouse <= 2) {
newValue = 0;
}
else {
newValue = skewSign * Math.atan((newDimMouse / target['scale' + _by]) /
(dimNoSkew[otherBy] / target['scale' + _otherBy]));
newValue = fabric.util.radiansToDegrees(newValue);
}
target.set('skew' + _by, newValue);
if (target['skew' + _otherBy] !== 0) {
newDim = target._getTransformedDimensions();
newValue = (_dim[otherBy] / newDim[otherBy]) * target['scale' + _otherBy];
target.set('scale' + _otherBy, newValue);
}
},
/**
* Scales object by invoking its scaleX/scaleY methods
* @private
@ -496,12 +619,13 @@
// Get the constraint point
var constraintPosition = target.translateToOriginPoint(target.getCenterPoint(), t.originX, t.originY),
localMouse = target.toLocalPoint(new fabric.Point(x, y), t.originX, t.originY);
localMouse = target.toLocalPoint(new fabric.Point(x, y), t.originX, t.originY),
dim = target._getTransformedDimensions();
this._setLocalMouse(localMouse, t);
// Actually scale the object
this._setObjectScale(localMouse, t, lockScalingX, lockScalingY, by, lockScalingFlip);
this._setObjectScale(localMouse, t, lockScalingX, lockScalingY, by, lockScalingFlip, dim);
// Make sure the constraints apply
target.setPositionByOrigin(constraintPosition, t.originX, t.originY);
@ -510,12 +634,11 @@
/**
* @private
*/
_setObjectScale: function(localMouse, transform, lockScalingX, lockScalingY, by, lockScalingFlip) {
var target = transform.target, forbidScalingX = false, forbidScalingY = false,
dim = target._getNonTransformedDimensions();
_setObjectScale: function(localMouse, transform, lockScalingX, lockScalingY, by, lockScalingFlip, _dim) {
var target = transform.target, forbidScalingX = false, forbidScalingY = false;
transform.newScaleX = localMouse.x / dim.x;
transform.newScaleY = localMouse.y / dim.y;
transform.newScaleX = localMouse.x * target.scaleX / _dim.x;
transform.newScaleY = localMouse.y * target.scaleY / _dim.y;
if (lockScalingFlip && transform.newScaleX <= 0 && transform.newScaleX < target.scaleX) {
forbidScalingX = true;
@ -526,7 +649,7 @@
}
if (by === 'equally' && !lockScalingX && !lockScalingY) {
forbidScalingX || forbidScalingY || this._scaleObjectEqually(localMouse, target, transform);
forbidScalingX || forbidScalingY || this._scaleObjectEqually(localMouse, target, transform, _dim);
}
else if (!by) {
forbidScalingX || lockScalingX || target.set('scaleX', transform.newScaleX);
@ -546,12 +669,11 @@
/**
* @private
*/
_scaleObjectEqually: function(localMouse, target, transform) {
_scaleObjectEqually: function(localMouse, target, transform, _dim) {
var dist = localMouse.y + localMouse.x,
dim = target._getNonTransformedDimensions(),
lastDist = dim.y * transform.original.scaleY +
dim.x * transform.original.scaleX;
lastDist = _dim.y * transform.original.scaleY / target.scaleY +
_dim.x * transform.original.scaleX / target.scaleX;
// We use transform.scaleX/Y instead of target.scaleX/Y
// because the object may have a min scale and we'll loose the proportions
@ -680,6 +802,8 @@
_resetObjectTransform: function (target) {
target.scaleX = 1;
target.scaleY = 1;
target.skewX = 0;
target.skewY = 0;
target.setAngle(0);
},

View file

@ -437,7 +437,7 @@
target = this.getActiveGroup();
}
if (target && target.selectable && !shouldGroup) {
if (target && target.selectable && (target.__corner || !shouldGroup)) {
this._beforeTransform(e, target);
this._setupCurrentTransform(e, target);
}
@ -617,6 +617,14 @@
this._scaleObject(x, y, 'y');
this._fire('scaling', target, e);
}
else if (action === 'skewX') {
this._skewObject(x, y, 'x');
this._fire('skewing', target, e);
}
else if (action === 'skewY') {
this._skewObject(x, y, 'y');
this._fire('skewing', target, e);
}
else {
this._translateObject(x, y);
this._fire('moving', target, e);
@ -637,14 +645,14 @@
*/
_beforeScaleTransform: function(e, transform) {
if (transform.action === 'scale' || transform.action === 'scaleX' || transform.action === 'scaleY') {
var centerTransform = this._shouldCenterTransform(e, transform.target);
var centerTransform = this._shouldCenterTransform(transform.target);
// Switch from a normal resize to center-based
if ((centerTransform && (transform.originX !== 'center' || transform.originY !== 'center')) ||
// Switch from center-based resize to normal one
(!centerTransform && transform.originX === 'center' && transform.originY === 'center')
) {
this._resetCurrentTransform(e);
this._resetCurrentTransform();
transform.reset = true;
}
}
@ -663,7 +671,7 @@
else {
// Switch from a normal resize to proportional
if (!transform.reset && transform.currentAction === 'scale') {
this._resetCurrentTransform(e, transform.target);
this._resetCurrentTransform();
}
transform.currentAction = 'scaleEqually';
@ -693,7 +701,7 @@
this.setCursor(target.hoverCursor || this.hoverCursor);
}
else {
this._setCornerCursor(corner, target);
this._setCornerCursor(corner, target, e);
}
}
return true;
@ -702,9 +710,9 @@
/**
* @private
*/
_setCornerCursor: function(corner, target) {
_setCornerCursor: function(corner, target, e) {
if (corner in cursorOffset) {
this.setCursor(this._getRotatedCornerCursor(corner, target));
this.setCursor(this._getRotatedCornerCursor(corner, target, e));
}
else if (corner === 'mtr' && target.hasRotatingPoint) {
this.setCursor(this.rotationCursor);
@ -718,13 +726,17 @@
/**
* @private
*/
_getRotatedCornerCursor: function(corner, target) {
_getRotatedCornerCursor: function(corner, target, e) {
var n = Math.round((target.getAngle() % 360) / 45);
if (n < 0) {
n += 8; // full circle ahead
}
n += cursorOffset[corner];
if (e.shiftKey && cursorOffset[corner] % 2 === 0) {
//if we are holding shift and we are on a mx corner...
n += 2;
}
// normalize n to be from 0 to 7
n %= 8;

View file

@ -58,6 +58,8 @@ fabric.util.object.extend(fabric.Object.prototype, /** @lends fabric.Object.prot
}
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),
@ -81,6 +83,10 @@ fabric.util.object.extend(fabric.Object.prototype, /** @lends fabric.Object.prot
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) ' : '',
@ -90,7 +96,7 @@ fabric.util.object.extend(fabric.Object.prototype, /** @lends fabric.Object.prot
flipYPart = this.flipY ? ' matrix(1 0 0 -1 0 ' + addTranslateY + ')' : '';
return [
translatePart, anglePart, scalePart, flipXPart, flipYPart
translatePart, anglePart, scalePart, flipXPart, flipYPart, skewXPart, skewYPart
].join('');
},

View file

@ -192,23 +192,12 @@
*/
getBoundingRect: function() {
this.oCoords || this.setCoords();
var xCoords = [this.oCoords.tl.x, this.oCoords.tr.x, this.oCoords.br.x, this.oCoords.bl.x],
minX = fabric.util.array.min(xCoords),
maxX = fabric.util.array.max(xCoords),
width = Math.abs(minX - maxX),
yCoords = [this.oCoords.tl.y, this.oCoords.tr.y, this.oCoords.br.y, this.oCoords.bl.y],
minY = fabric.util.array.min(yCoords),
maxY = fabric.util.array.max(yCoords),
height = Math.abs(minY - maxY);
return {
left: minX,
top: minY,
width: width,
height: height
};
return fabric.util.makeBoundingBoxFromPoints([
this.oCoords.tl,
this.oCoords.tr,
this.oCoords.br,
this.oCoords.bl
]);
},
/**
@ -217,7 +206,7 @@
*/
getWidth: function() {
//needs to be changed
return this.width * this.scaleX;
return this._getTransformedDimensions().x;
},
/**
@ -226,7 +215,7 @@
*/
getHeight: function() {
//needs to be changed
return this.height * this.scaleY;
return this._getTransformedDimensions().y;
},
/**
@ -357,9 +346,12 @@
return this;
},
_calcDimensionsTransformMatrix: function() {
// introduce skew matrix here later
return [this.scaleX, 0, 0, this.scaleY, 0, 0];
_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);
}
});
})();

View file

@ -138,12 +138,39 @@
/*
* @private
*/
_getTransformedDimensions: function(dimensions) {
if (!dimensions) {
dimensions = this._getNonTransformedDimensions();
_getTransformedDimensions: function(skewX, skewY) {
if (typeof skewX === 'undefined') {
skewX = this.skewX;
}
var transformMatrix = this._calcDimensionsTransformMatrix();
return fabric.util.transformPoint(dimensions, transformMatrix, true);
if (typeof skewY === 'undefined') {
skewY = this.skewY;
}
var dimensions = this._getNonTransformedDimensions(),
dimX = dimensions.x /2, dimY = dimensions.y / 2,
points = [
{
x: -dimX,
y: -dimY
},
{
x: dimX,
y: -dimY
},
{
x: -dimX,
y: dimY
},
{
x: dimX,
y: dimY
}],
i, transformMatrix = this._calcDimensionsTransformMatrix(skewX, skewY),
bbox;
for (i = 0; i < points.length; i++) {
points[i] = fabric.util.transformPoint(points[i], transformMatrix);
}
bbox = fabric.util.makeBoundingBoxFromPoints(points);
return { x: bbox.width, y: bbox.height };
},
/*

View file

@ -7,7 +7,7 @@
var setObjectScaleOverridden = fabric.Canvas.prototype._setObjectScale;
fabric.Canvas.prototype._setObjectScale = function(localMouse, transform,
lockScalingX, lockScalingY, by, lockScalingFlip) {
lockScalingX, lockScalingY, by, lockScalingFlip, _dim) {
var t = transform.target;
if (t instanceof fabric.Textbox) {
@ -18,7 +18,7 @@
}
else {
setObjectScaleOverridden.call(fabric.Canvas.prototype, localMouse, transform,
lockScalingX, lockScalingY, by, lockScalingFlip);
lockScalingX, lockScalingY, by, lockScalingFlip, _dim);
}
};

View file

@ -27,6 +27,7 @@
* @fires rotating
* @fires scaling
* @fires moving
* @fires skewing
*
* @fires mousedown
* @fires mouseup
@ -382,6 +383,20 @@
*/
angle: 0,
/**
* Angle of skew on x axes of an object (in degrees)
* @type Number
* @default
*/
skewX: 0,
/**
* Angle of skew on y axes of an object (in degrees)
* @type Number
* @default
*/
skewY: 0,
/**
* Size of object's controlling corners (in pixels)
* @type Number
@ -662,6 +677,20 @@
*/
lockUniScaling: false,
/**
* When `true`, object horizontal skewing is locked
* @type Boolean
* @default
*/
lockSkewingX: false,
/**
* When `true`, object vertical skewing is locked
* @type Boolean
* @default
*/
lockSkewingY: false,
/**
* When `true`, object cannot be flipped by scaling into negative values
* @type Boolean
@ -679,7 +708,7 @@
'top left width height scaleX scaleY flipX flipY originX originY transformMatrix ' +
'stroke strokeWidth strokeDashArray strokeLineCap strokeLineJoin strokeMiterLimit ' +
'angle opacity fill fillRule globalCompositeOperation shadow clipTo visible backgroundColor ' +
'alignX alignY meetOrSlice'
'alignX alignY meetOrSlice skewX skewY'
).split(' '),
/**
@ -762,6 +791,8 @@
this.scaleX * (this.flipX ? -1 : 1),
this.scaleY * (this.flipY ? -1 : 1)
);
ctx.transform(1, 0, Math.tan(degreesToRadians(this.skewX)), 1, 0, 0);
ctx.transform(1, Math.tan(degreesToRadians(this.skewY)), 0, 1, 0, 0);
},
/**
@ -799,7 +830,9 @@
backgroundColor: this.backgroundColor,
fillRule: this.fillRule,
globalCompositeOperation: this.globalCompositeOperation,
transformMatrix: this.transformMatrix ? this.transformMatrix.concat() : this.transformMatrix
transformMatrix: this.transformMatrix ? this.transformMatrix.concat() : this.transformMatrix,
skewX: toFixed(this.skewX, NUM_FRACTION_DIGITS),
skewY: toFixed(this.skewY, NUM_FRACTION_DIGITS)
};
if (!this.includeDefaultValues) {

View file

@ -2,6 +2,8 @@
var sqrt = Math.sqrt,
atan2 = Math.atan2,
atan = Math.atan,
pow = Math.pow,
PiBy180 = Math.PI / 180;
/**
@ -100,6 +102,29 @@
);
},
/**
* Returns coordinates of points's bounding rectangle (left, top, width, height)
* @param {Array} points 4 points array
* @return {Object} Object with left, top, width, height properties
*/
makeBoundingBoxFromPoints: function(points) {
var xPoints = [points[0].x, points[1].x, points[2].x, points[3].x],
minX = fabric.util.array.min(xPoints),
maxX = fabric.util.array.max(xPoints),
width = Math.abs(minX - maxX),
yPoints = [points[0].y, points[1].y, points[2].y, points[3].y],
minY = fabric.util.array.min(yPoints),
maxY = fabric.util.array.max(yPoints),
height = Math.abs(minY - maxY);
return {
left: minX,
top: minY,
width: width,
height: height
};
},
/**
* Invert transformation t
* @static
@ -457,20 +482,43 @@
* @memberOf fabric.util
* @param {Array} a First transformMatrix
* @param {Array} b Second transformMatrix
* @param {Boolean} is2x2 flag to multiply matrices as 2x2 matrices
* @return {Array} The product of the two transform matrices
*/
multiplyTransformMatrices: function(a, b) {
multiplyTransformMatrices: function(a, b, is2x2) {
// Matrix multiply a * b
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],
a[0] * b[4] + a[2] * b[5] + a[4],
a[1] * b[4] + a[3] * b[5] + a[5]
is2x2 ? 0 : a[0] * b[4] + a[2] * b[5] + a[4],
is2x2 ? 0 : a[1] * b[4] + a[3] * b[5] + a[5]
];
},
/**
* Decompone standard 2x2 matrix into transform componentes
* @static
* @memberOf fabric.util
* @param {Array} a transformMatrix
* @return {Object} Components of transform
*/
qrDecompone: 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);
return {
angle: angle / PiBy180,
scaleX: scaleX,
scaleY: scaleY,
skewX: skewX / PiBy180,
skewY: 0
};
},
/**
* Returns string representation of function body
* @param {Function} fn Function to get body of

View file

@ -41,12 +41,12 @@
var PATH_DATALESS_JSON = '{"objects":[{"type":"path","originX":"left","originY":"top","left":100,"top":100,"width":200,"height":200,"fill":"rgb(0,0,0)",'+
'"stroke":null,"strokeWidth":1,"strokeDashArray":null,"strokeLineCap":"butt","strokeLineJoin":"miter","strokeMiterLimit":10,'+
'"scaleX":1,"scaleY":1,"angle":0,"flipX":false,"flipY":false,"opacity":1,'+
'"shadow":null,"visible":true,"clipTo":null,"backgroundColor":"","fillRule":"nonzero","globalCompositeOperation":"source-over","transformMatrix":null,"path":"http://example.com/","pathOffset":{"x":200,"y":200}}],"background":""}';
'"shadow":null,"visible":true,"clipTo":null,"backgroundColor":"","fillRule":"nonzero","globalCompositeOperation":"source-over","transformMatrix":null,"skewX":0,"skewY":0,"path":"http://example.com/","pathOffset":{"x":200,"y":200}}],"background":""}';
var RECT_JSON = '{"objects":[{"type":"rect","originX":"left","originY":"top","left":0,"top":0,"width":10,"height":10,"fill":"rgb(0,0,0)",'+
'"stroke":null,"strokeWidth":1,"strokeDashArray":null,"strokeLineCap":"butt","strokeLineJoin":"miter","strokeMiterLimit":10,"scaleX":1,"scaleY":1,"angle":0,"flipX":false,"flipY":false,"opacity":1,'+
'"shadow":null,'+
'"visible":true,"clipTo":null,"backgroundColor":"","fillRule":"nonzero","globalCompositeOperation":"source-over","transformMatrix":null,"rx":0,"ry":0}],"background":"#ff5555","overlay":"rgba(0,0,0,0.2)"}';
'"visible":true,"clipTo":null,"backgroundColor":"","fillRule":"nonzero","globalCompositeOperation":"source-over","transformMatrix":null,"skewX":0,"skewY":0,"rx":0,"ry":0}],"background":"#ff5555","overlay":"rgba(0,0,0,0.2)"}';
var el = fabric.document.createElement('canvas');
el.width = 600; el.height = 600;

View file

@ -28,17 +28,17 @@
var PATH_DATALESS_JSON = '{"objects":[{"type":"path","originX":"left","originY":"top","left":100,"top":100,"width":200,"height":200,"fill":"rgb(0,0,0)",'+
'"stroke":null,"strokeWidth":1,"strokeDashArray":null,"strokeLineCap":"butt","strokeLineJoin":"miter","strokeMiterLimit":10,'+
'"scaleX":1,"scaleY":1,"angle":0,"flipX":false,"flipY":false,"opacity":1,'+
'"shadow":null,"visible":true,"clipTo":null,"backgroundColor":"","fillRule":"nonzero","globalCompositeOperation":"source-over","transformMatrix":null,"path":"http://example.com/","pathOffset":{"x":200,"y":200}}],"background":""}';
'"shadow":null,"visible":true,"clipTo":null,"backgroundColor":"","fillRule":"nonzero","globalCompositeOperation":"source-over","transformMatrix":null,"skewX":0,"skewY":0,"path":"http://example.com/","pathOffset":{"x":200,"y":200}}],"background":""}';
var RECT_JSON = '{"objects":[{"type":"rect","originX":"left","originY":"top","left":0,"top":0,"width":10,"height":10,"fill":"rgb(0,0,0)",'+
'"stroke":null,"strokeWidth":1,"strokeDashArray":null,"strokeLineCap":"butt","strokeLineJoin":"miter","strokeMiterLimit":10,'+
'"scaleX":1,"scaleY":1,"angle":0,"flipX":false,"flipY":false,"opacity":1,'+
'"shadow":null,"visible":true,"clipTo":null,"backgroundColor":"","fillRule":"nonzero","globalCompositeOperation":"source-over","transformMatrix":null,"rx":0,"ry":0}],"background":"#ff5555","overlay":"rgba(0,0,0,0.2)"}';
'"shadow":null,"visible":true,"clipTo":null,"backgroundColor":"","fillRule":"nonzero","globalCompositeOperation":"source-over","transformMatrix":null,"skewX":0,"skewY":0,"rx":0,"ry":0}],"background":"#ff5555","overlay":"rgba(0,0,0,0.2)"}';
var RECT_JSON_WITH_PADDING = '{"objects":[{"type":"rect","originX":"left","originY":"top","left":0,"top":0,"width":10,"height":20,"fill":"rgb(0,0,0)",'+
'"stroke":null,"strokeWidth":1,"strokeDashArray":null,"strokeLineCap":"butt","strokeLineJoin":"miter","strokeMiterLimit":10,'+
'"scaleX":1,"scaleY":1,"angle":0,"flipX":false,"flipY":false,"opacity":1,'+
'"shadow":null,"visible":true,"clipTo":null,"backgroundColor":"","fillRule":"nonzero","globalCompositeOperation":"source-over","transformMatrix":null,"padding":123,"foo":"bar","rx":0,"ry":0}],"background":""}';
'"shadow":null,"visible":true,"clipTo":null,"backgroundColor":"","fillRule":"nonzero","globalCompositeOperation":"source-over","transformMatrix":null,"skewX":0,"skewY":0,"padding":123,"foo":"bar","rx":0,"ry":0}],"background":""}';
function getAbsolutePath(path) {
var isAbsolute = /^https?:/.test(path);
@ -85,6 +85,8 @@
'globalCompositeOperation': 'source-over',
'transformMatrix': null,
'crossOrigin': '',
'skewX': 0,
'skewY': 0,
'alignX': 'none',
'alignY': 'none',
'meetOrSlice': 'meet'

View file

@ -39,7 +39,7 @@
});
test('setRadius', function() {
var circle = new fabric.Circle({ radius: 10 });
var circle = new fabric.Circle({radius: 10, strokeWidth: 0});
ok(typeof circle.setRadius == 'function');
@ -59,7 +59,7 @@
});
test('set radius', function() {
var circle = new fabric.Circle();
var circle = new fabric.Circle({strokeWidth: 0});
circle.set('radius', 20);
@ -108,6 +108,8 @@
'radius': 0,
'startAngle': 0,
'endAngle': 2 * Math.PI,
'skewX': 0,
'skewY': 0,
'transformMatrix': null
};
ok(typeof circle.toObject == 'function');
@ -218,7 +220,7 @@
});
test('cloning and radius, width, height', function() {
var circle = new fabric.Circle({ radius: 10 });
var circle = new fabric.Circle({ radius: 10, strokeWidth: 0});
circle.scale(2);
var clone = circle.clone();

View file

@ -42,6 +42,8 @@
'flipX': false,
'flipY': false,
'opacity': 1,
'skewX': 0,
'skewY': 0,
'rx': 0,
'ry': 0,
'shadow': null,

View file

@ -191,6 +191,8 @@
'fillRule': 'nonzero',
'globalCompositeOperation': 'source-over',
'transformMatrix': null,
'skewX': 0,
'skewY': 0,
'objects': clone.objects
};

View file

@ -43,6 +43,8 @@
'filters': [],
'fillRule': 'nonzero',
'globalCompositeOperation': 'source-over',
'skewX': 0,
'skewY': 0,
'transformMatrix': null,
'crossOrigin': '',
'alignX': 'none',

View file

@ -43,6 +43,8 @@
'textBackgroundColor': '',
'fillRule': 'nonzero',
'globalCompositeOperation': 'source-over',
'skewX': 0,
'skewY': 0,
'transformMatrix': null,
styles: { }
};

View file

@ -31,6 +31,8 @@
'backgroundColor': '',
'fillRule': 'nonzero',
'globalCompositeOperation': 'source-over',
'skewX': 0,
'skewY': 0,
'transformMatrix': null
};

View file

@ -154,13 +154,13 @@
'"stroke":null,"strokeWidth":1,"strokeDashArray":null,"strokeLineCap":"butt","strokeLineJoin":"miter","strokeMiterLimit":10,'+
'"scaleX":1,"scaleY":1,"angle":0,"flipX":false,"flipY":false,"opacity":1,'+
'"shadow":null,"visible":true,"clipTo":null,"backgroundColor":"","fillRule":"nonzero","globalCompositeOperation":"source-over",'+
'"transformMatrix":null}';
'"transformMatrix":null,"skewX":0,"skewY":0}';
var augmentedJSON = '{"type":"object","originX":"left","originY":"top","left":0,"top":0,"width":122,"height":0,"fill":"rgb(0,0,0)",'+
'"stroke":null,"strokeWidth":1,"strokeDashArray":[5,2],"strokeLineCap":"round","strokeLineJoin":"bevil","strokeMiterLimit":5,'+
'"scaleX":1.3,"scaleY":1,"angle":0,"flipX":false,"flipY":true,"opacity":0.88,'+
'"shadow":null,"visible":true,"clipTo":null,"backgroundColor":"","fillRule":"nonzero","globalCompositeOperation":"source-over",'+
'"transformMatrix":null}';
'"transformMatrix":null,"skewX":0,"skewY":0}';
var cObj = new fabric.Object();
ok(typeof cObj.toJSON == 'function');
@ -206,6 +206,8 @@
'clipTo': null,
'fillRule': 'nonzero',
'globalCompositeOperation': 'source-over',
'skewX': 0,
'skewY': 0,
'transformMatrix': null
};
@ -236,7 +238,9 @@
'clipTo': null,
'fillRule': 'nonzero',
'globalCompositeOperation': 'source-over',
'transformMatrix': null
'transformMatrix': null,
'skewX': 0,
'skewY': 0
};
var cObj = new fabric.Object();
@ -408,17 +412,17 @@ test('getBoundingRectWithStroke', function() {
});
test('getWidth', function() {
var cObj = new fabric.Object({ strokeWidth: 0 });
var cObj = new fabric.Object();
ok(typeof cObj.getWidth == 'function');
equal(cObj.getWidth(), 0);
equal(cObj.getWidth(), 0 + cObj.strokeWidth);
cObj.set('width', 123);
equal(cObj.getWidth(), 123);
equal(cObj.getWidth(), 123 + cObj.strokeWidth);
cObj.set('scaleX', 2);
equal(cObj.getWidth(), 246);
equal(cObj.getWidth(), 246 + cObj.strokeWidth * 2);
});
test('getHeight', function() {
var cObj = new fabric.Object();
var cObj = new fabric.Object({strokeWidth: 0});
ok(typeof cObj.getHeight == 'function');
equal(cObj.getHeight(), 0);
cObj.set('height', 123);

View file

@ -237,6 +237,7 @@
var rect = new fabric.Rect(rectOptions),
p;
rect.strokeWidth = 0;
rect.originX = 'left';
rect.originY = 'top';
p = rect.adjustPosition('left');
@ -294,7 +295,7 @@
p;
rect.angle = 35;
rect.strokeWidth = 0;
rect.originX = 'left';
rect.originY = 'top';
p = rect.adjustPosition('left');

View file

@ -29,6 +29,8 @@
'clipTo': null,
'fillRule': 'nonzero',
'globalCompositeOperation': 'source-over',
'skewX': 0,
'skewY': 0,
'transformMatrix': null
};

View file

@ -28,6 +28,8 @@
'fillRule': 'nonzero',
'globalCompositeOperation': 'source-over',
'transformMatrix': null,
'skewX': 0,
'skewY': 0,
'paths': getPathObjects()
};

View file

@ -35,6 +35,8 @@
'clipTo': null,
'fillRule': 'nonzero',
'globalCompositeOperation': 'source-over',
'skewX': 0,
'skewY': 0,
'transformMatrix': null
};

View file

@ -35,6 +35,8 @@
'clipTo': null,
'fillRule': 'nonzero',
'globalCompositeOperation': 'source-over',
'skewX': 0,
'skewY': 0,
'transformMatrix': null
};

View file

@ -28,10 +28,10 @@
'fillRule': 'nonzero',
'globalCompositeOperation': 'source-over',
'transformMatrix': null,
'skewX': 0,
'skewY': 0,
'rx': 0,
'ry': 0,
'skewX': 0,
'skewY': 0,
};
QUnit.module('fabric.Rect');
@ -104,7 +104,6 @@
elRectWithAttrs.setAttribute('stroke-linecap', 'round');
elRectWithAttrs.setAttribute('stroke-linejoin', 'bevil');
elRectWithAttrs.setAttribute('stroke-miterlimit', 5);
elRectWithAttrs.setAttribute('skewX', 30);
//elRectWithAttrs.setAttribute('transform', 'translate(-10,-20) scale(2) rotate(45) translate(5,10)');
var rectWithAttrs = fabric.Rect.fromElement(elRectWithAttrs);
@ -123,7 +122,6 @@
strokeLineCap: 'round',
strokeLineJoin: 'bevil',
strokeMiterLimit: 5,
skewX: 30,
rx: 11,
ry: 12
});

View file

@ -44,6 +44,8 @@
'textBackgroundColor': '',
'fillRule': 'nonzero',
'globalCompositeOperation': 'source-over',
'skewX': 0,
'skewY': 0,
'transformMatrix': null
};
@ -154,8 +156,8 @@
// text.width = CHAR_WIDTH;
var expectedObject = fabric.util.object.extend(fabric.util.object.clone(REFERENCE_TEXT_OBJECT), {
left: 4,
top: -3.61,
left: 4.5,
top: -4.11,
width: 8,
height: 20.97,
fontSize: 16,
@ -196,7 +198,7 @@
var expectedObject = fabric.util.object.extend(fabric.util.object.clone(REFERENCE_TEXT_OBJECT), {
/* left varies slightly due to node-canvas rendering */
left: fabric.util.toFixed(textWithAttrs.left + '', 2),
top: -7.72,
top: -9.22,
width: CHAR_WIDTH,
height: 161.23,
fill: 'rgb(255,255,255)',