Fix unit tests. Add loadFromJSON test for previous fix. Version 0.9.5.

This commit is contained in:
kangax 2012-09-02 12:28:52 -04:00
parent 5f19d75a03
commit 762cfb7b8a
8 changed files with 250 additions and 98 deletions

View file

@ -1,6 +1,6 @@
/*! Fabric.js Copyright 2008-2012, Printio (Juriy Zaytsev, Maxim Chernyak) */
var fabric = fabric || { version: "0.9.4" };
var fabric = fabric || { version: "0.9.5" };
if (typeof exports != 'undefined') {
exports.fabric = fabric;

294
dist/all.js vendored
View file

@ -1,7 +1,7 @@
/* build: `node build.js modules=ALL` */
/*! Fabric.js Copyright 2008-2012, Printio (Juriy Zaytsev, Maxim Chernyak) */
var fabric = fabric || { version: "0.9.4" };
var fabric = fabric || { version: "0.9.5" };
if (typeof exports != 'undefined') {
exports.fabric = fabric;
@ -1984,14 +1984,17 @@ fabric.Observable.off = fabric.Observable.stopObserving;
return fabric[fabric.util.string.camelize(fabric.util.string.capitalize(type))];
}
var enlivenedObjects = [ ],
numLoadedAsyncObjects = 0,
// get length of all images
numTotalAsyncObjects = objects.filter(function (o) {
return getKlass(o.type).async;
}).length;
function onLoaded() {
if (++numLoadedObjects === numTotalObjects) {
if (callback) {
callback(enlivenedObjects);
}
}
}
var _this = this;
var enlivenedObjects = [ ],
numLoadedObjects = 0,
numTotalObjects = objects.length;
objects.forEach(function (o, index) {
if (!o.type) {
@ -2001,21 +2004,14 @@ fabric.Observable.off = fabric.Observable.stopObserving;
if (klass.async) {
klass.fromObject(o, function (o) {
enlivenedObjects[index] = o;
if (++numLoadedAsyncObjects === numTotalAsyncObjects) {
if (callback) {
callback(enlivenedObjects);
}
}
onLoaded();
});
}
else {
enlivenedObjects[index] = klass.fromObject(o);
onLoaded();
}
});
if (numTotalAsyncObjects === 0 && callback) {
callback(enlivenedObjects);
}
}
function groupSVGElements(elements, options, path) {
@ -6549,7 +6545,7 @@ fabric.util.string = {
ey: pointer.y,
left: target.left,
top: target.top,
theta: target.theta,
theta: target._theta,
width: target.width * target.scaleX
};
@ -6752,7 +6748,7 @@ fabric.util.string = {
var lastAngle = atan2(t.ey - t.top - o.top, t.ex - t.left - o.left),
curAngle = atan2(y - t.top - o.top, x - t.left - o.left);
t.target.set('theta', (curAngle - lastAngle) + t.theta);
t.target._theta = (curAngle - lastAngle) + t.theta;
},
/**
@ -7531,60 +7527,143 @@ fabric.util.object.extend(fabric.StaticCanvas.prototype, {
*/
type: 'object',
/**
* @property
* @type Number
*/
top: 0,
/**
* @property
* @type Number
*/
left: 0,
/**
* @property
* @type Number
*/
width: 0,
/**
* @property
* @type Number
*/
height: 0,
/**
* @property
* @type Number
*/
scaleX: 1,
/**
* @property
* @type Number
*/
scaleY: 1,
/**
* @property
* @type Boolean
*/
includeDefaultValues: true,
flipX: false,
/**
* @constant
* @property
* @type Boolean
*/
flipY: false,
/**
* @property
* @type Number
*/
NUM_FRACTION_DIGITS: 2,
opacity: 1,
/**
* @constant
* @property
* @type Number
*/
MIN_SCALE_LIMIT: 0.1,
angle: 0,
/**
* @property
* @type Number
*/
cornersize: 12,
/**
* @property
* @type Number
*/
padding: 0,
/**
* @property
* @type String
*/
borderColor: 'rgba(102,153,255,0.75)',
/**
* @property
* @type String
*/
cornerColor: 'rgba(102,153,255,0.5)',
/**
* @property
* @type String
*/
fill: 'rgb(0,0,0)',
/**
* @property
* @type String
*/
fillRule: 'source-over',
/**
* @property
* @type String
*/
overlayFill: null,
/**
* @property
* @type String
*/
stroke: null,
/**
* @property
* @type Number
*/
strokeWidth: 1,
/**
* List of properties to consider when checking if state of an object is changed (fabric.Object#hasStateChanged);
* as well as for history (undo/redo) purposes
* @property
* @type Array
*/
stateProperties: (
'top left width height scaleX scaleY flipX flipY ' +
'theta angle opacity cornersize fill overlayFill ' +
'stroke strokeWidth strokeDashArray fillRule ' +
'borderScaleFactor transformMatrix selectable'
).split(' '),
top: 0,
left: 0,
width: 0,
height: 0,
scaleX: 1,
scaleY: 1,
flipX: false,
flipY: false,
theta: 0,
opacity: 1,
angle: 0,
cornersize: 12,
padding: 0,
borderColor: 'rgba(102,153,255,0.75)',
cornerColor: 'rgba(102,153,255,0.5)',
fill: 'rgb(0,0,0)',
fillRule: 'source-over',
overlayFill: null,
stroke: null,
strokeWidth: 1,
strokeDashArray: null,
/**
* @property
* @type Number
*/
borderOpacityWhenMoving: 0.4,
/**
* @property
* @type Number
*/
borderScaleFactor: 1,
/**
* Transform matrix
* @property
* @type Array
*/
transformMatrix: null,
/**
@ -7622,6 +7701,28 @@ fabric.util.object.extend(fabric.StaticCanvas.prototype, {
*/
rotatingPointOffset: 40,
/**
* @private
* @property
* @type Number
*/
_theta: 0,
includeDefaultValues: true,
/**
* List of properties to consider when checking if state of an object is changed (fabric.Object#hasStateChanged);
* as well as for history (undo/redo) purposes
* @property
* @type Array
*/
stateProperties: (
'top left width height scaleX scaleY flipX flipY ' +
'theta angle opacity cornersize fill overlayFill ' +
'stroke strokeWidth strokeDashArray fillRule ' +
'borderScaleFactor transformMatrix selectable'
).split(' '),
/**
* @method callSuper
* @param {String} methodName
@ -7675,7 +7776,7 @@ fabric.util.object.extend(fabric.StaticCanvas.prototype, {
transform: function(ctx) {
ctx.globalAlpha = this.opacity;
ctx.translate(this.left, this.top);
ctx.rotate(this.theta);
ctx.rotate(this._theta);
ctx.scale(
this.scaleX * (this.flipX ? -1 : 1),
this.scaleY * (this.flipY ? -1 : 1)
@ -7689,23 +7790,25 @@ fabric.util.object.extend(fabric.StaticCanvas.prototype, {
*/
toObject: function() {
var NUM_FRACTION_DIGITS = fabric.Object.NUM_FRACTION_DIGITS;
var object = {
type: this.type,
left: toFixed(this.left, this.NUM_FRACTION_DIGITS),
top: toFixed(this.top, this.NUM_FRACTION_DIGITS),
width: toFixed(this.width, this.NUM_FRACTION_DIGITS),
height: toFixed(this.height, this.NUM_FRACTION_DIGITS),
left: toFixed(this.left, NUM_FRACTION_DIGITS),
top: toFixed(this.top, NUM_FRACTION_DIGITS),
width: toFixed(this.width, NUM_FRACTION_DIGITS),
height: toFixed(this.height, NUM_FRACTION_DIGITS),
fill: (this.fill && this.fill.toObject) ? this.fill.toObject() : this.fill,
overlayFill: this.overlayFill,
stroke: this.stroke,
strokeWidth: this.strokeWidth,
strokeDashArray: this.strokeDashArray,
scaleX: toFixed(this.scaleX, this.NUM_FRACTION_DIGITS),
scaleY: toFixed(this.scaleY, this.NUM_FRACTION_DIGITS),
angle: toFixed(this.getAngle(), this.NUM_FRACTION_DIGITS),
scaleX: toFixed(this.scaleX, NUM_FRACTION_DIGITS),
scaleY: toFixed(this.scaleY, NUM_FRACTION_DIGITS),
angle: toFixed(this.getAngle(), NUM_FRACTION_DIGITS),
flipX: this.flipX,
flipY: this.flipY,
opacity: toFixed(this.opacity, this.NUM_FRACTION_DIGITS),
opacity: toFixed(this.opacity, NUM_FRACTION_DIGITS),
selectable: this.selectable,
hasControls: this.hasControls,
hasBorders: this.hasBorders,
@ -7827,10 +7930,10 @@ fabric.util.object.extend(fabric.StaticCanvas.prototype, {
_set: function(key, value) {
var shouldConstrainValue = (key === 'scaleX' || key === 'scaleY') &&
value < this.MIN_SCALE_LIMIT;
value < fabric.Object.MIN_SCALE_LIMIT;
if (shouldConstrainValue) {
value = this.MIN_SCALE_LIMIT;
value = fabric.Object.MIN_SCALE_LIMIT;
}
if (key === 'angle') {
this.setAngle(value);
@ -8009,7 +8112,7 @@ fabric.util.object.extend(fabric.StaticCanvas.prototype, {
* @return {Number} angle value
*/
getAngle: function() {
return this.theta * 180 / Math.PI;
return this._theta * 180 / Math.PI;
},
/**
@ -8019,7 +8122,7 @@ fabric.util.object.extend(fabric.StaticCanvas.prototype, {
* @return {Object} thisArg
*/
setAngle: function(value) {
this.theta = value / 180 * Math.PI;
this._theta = value / 180 * Math.PI;
this.angle = value;
return this;
},
@ -8032,8 +8135,10 @@ fabric.util.object.extend(fabric.StaticCanvas.prototype, {
*/
setCoords: function() {
this.currentWidth = (this.width + this.strokeWidth) * this.scaleX;
this.currentHeight = (this.height + this.strokeWidth) * this.scaleY;
var strokeWidth = this.strokeWidth > 1 ? this.strokeWidth : 0;
this.currentWidth = (this.width + strokeWidth) * this.scaleX;
this.currentHeight = (this.height + strokeWidth) * this.scaleY;
this._hypotenuse = Math.sqrt(
Math.pow(this.currentWidth / 2, 2) +
@ -8042,9 +8147,9 @@ fabric.util.object.extend(fabric.StaticCanvas.prototype, {
this._angle = Math.atan(this.currentHeight / this.currentWidth);
// offset added for rotate and scale actions
var offsetX = Math.cos(this._angle + this.theta) * this._hypotenuse,
offsetY = Math.sin(this._angle + this.theta) * this._hypotenuse,
theta = this.theta,
var offsetX = Math.cos(this._angle + this._theta) * this._hypotenuse,
offsetY = Math.sin(this._angle + this._theta) * this._hypotenuse,
theta = this._theta,
sinTh = Math.sin(theta),
cosTh = Math.cos(theta);
@ -8144,15 +8249,17 @@ fabric.util.object.extend(fabric.StaticCanvas.prototype, {
drawBorders: function(ctx) {
if (!this.hasBorders) return;
var padding2 = this.padding * 2;
var padding2 = this.padding * 2,
MIN_SCALE_LIMIT = fabric.Object.MIN_SCALE_LIMIT,
strokeWidth = this.strokeWidth > 1 ? this.strokeWidth : 0;
ctx.save();
ctx.globalAlpha = this.isMoving ? this.borderOpacityWhenMoving : 1;
ctx.strokeStyle = this.borderColor;
var scaleX = 1 / (this.scaleX < this.MIN_SCALE_LIMIT ? this.MIN_SCALE_LIMIT : this.scaleX),
scaleY = 1 / (this.scaleY < this.MIN_SCALE_LIMIT ? this.MIN_SCALE_LIMIT : this.scaleY);
var scaleX = 1 / (this.scaleX < MIN_SCALE_LIMIT ? MIN_SCALE_LIMIT : this.scaleX),
scaleY = 1 / (this.scaleY < MIN_SCALE_LIMIT ? MIN_SCALE_LIMIT : this.scaleY);
ctx.lineWidth = 1 / this.borderScaleFactor;
@ -8162,14 +8269,14 @@ fabric.util.object.extend(fabric.StaticCanvas.prototype, {
h = this.getHeight();
ctx.strokeRect(
~~(-(w / 2) - this.padding - this.strokeWidth / 2 * this.scaleX) + 0.5, // offset needed to make lines look sharper
~~(-(h / 2) - this.padding - this.strokeWidth / 2 * this.scaleY) + 0.5,
~~(w + padding2 + this.strokeWidth * this.scaleX),
~~(h + padding2 + this.strokeWidth * this.scaleY)
~~(-(w / 2) - this.padding - strokeWidth / 2 * this.scaleX) + 0.5, // offset needed to make lines look sharper
~~(-(h / 2) - this.padding - strokeWidth / 2 * this.scaleY) + 0.5,
~~(w + padding2 + strokeWidth * this.scaleX),
~~(h + padding2 + strokeWidth * this.scaleY)
);
if (this.hasRotatingPoint && !this.hideCorners && !this.lockRotation) {
var rotateHeight = (this.flipY ? h : -h) / 2;
var rotateHeight = (this.flipY ? h + strokeWidth * this.scaleY : -h - strokeWidth * this.scaleY) / 2;
var rotateWidth = (-w/2);
ctx.beginPath();
@ -8327,7 +8434,7 @@ fabric.util.object.extend(fabric.StaticCanvas.prototype, {
_left = left + this.width/2 - scaleOffsetX;
_top = this.flipY ?
(top + height + (this.rotatingPointOffset / this.scaleY) - sizeY/2 - strokeWidth2)
(top + height + (this.rotatingPointOffset / this.scaleY) - sizeY/2 + strokeWidth2)
: (top - (this.rotatingPointOffset / this.scaleY) - sizeY/2 - strokeWidth2);
ctx.fillRect(_left, _top, sizeX, sizeY);
@ -8682,8 +8789,8 @@ fabric.util.object.extend(fabric.StaticCanvas.prototype, {
cornerHypotenuse = Math.sqrt(2 * Math.pow(this.cornersize, 2)) / 2,
cosHalfOffset = cornerHypotenuse * Math.cos(theta),
sinHalfOffset = cornerHypotenuse * Math.sin(theta),
sinTh = Math.sin(this.theta),
cosTh = Math.cos(this.theta);
sinTh = Math.sin(this._theta),
cosTh = Math.cos(this._theta);
coords.tl.corner = {
tl: {
@ -9036,6 +9143,24 @@ fabric.util.object.extend(fabric.StaticCanvas.prototype, {
extend(fabric.Object.prototype, fabric.Observable);
extend(fabric.Object, {
/**
* @static
* @constant
* @type Number
*/
NUM_FRACTION_DIGITS: 2,
/**
* @static
* @constant
* @type Number
*/
MIN_SCALE_LIMIT: 0.1
});
})(typeof exports != 'undefined' ? exports : this);
(function(global) {
@ -10070,8 +10195,9 @@ fabric.util.object.extend(fabric.StaticCanvas.prototype, {
maxX = max(points, 'x'),
maxY = max(points, 'y');
this.width = maxX - minX;
this.height = maxY - minY;
this.width = (maxX - minX) || 1;
this.height = (maxY - minY) || 1;
this.minX = minX;
this.minY = minY;
},

4
dist/all.min.js vendored

File diff suppressed because one or more lines are too long

BIN
dist/all.min.js.gz vendored

Binary file not shown.

View file

@ -1,7 +1,7 @@
{
"name": "fabric",
"description": "Object model for HTML5 canvas, and SVG-to-canvas parser. Backed by jsdom and node-canvas.",
"version": "0.9.4",
"version": "0.9.5",
"author": "Juriy Zaytsev <kangax@gmail.com>",
"keywords": ["canvas", "graphic", "graphics", "SVG", "node-canvas", "parser", "HTML5", "object model"],
"repository": "git://github.com/kangax/fabric.js",

View file

@ -209,6 +209,8 @@
*/
_theta: 0,
includeDefaultValues: true,
/**
* List of properties to consider when checking if state of an object is changed (fabric.Object#hasStateChanged);
* as well as for history (undo/redo) purposes
@ -634,8 +636,10 @@
*/
setCoords: function() {
this.currentWidth = (this.width + this.strokeWidth) * this.scaleX;
this.currentHeight = (this.height + this.strokeWidth) * this.scaleY;
var strokeWidth = this.strokeWidth > 1 ? this.strokeWidth : 0;
this.currentWidth = (this.width + strokeWidth) * this.scaleX;
this.currentHeight = (this.height + strokeWidth) * this.scaleY;
this._hypotenuse = Math.sqrt(
Math.pow(this.currentWidth / 2, 2) +
@ -747,7 +751,8 @@
if (!this.hasBorders) return;
var padding2 = this.padding * 2,
MIN_SCALE_LIMIT = fabric.Object.MIN_SCALE_LIMIT;
MIN_SCALE_LIMIT = fabric.Object.MIN_SCALE_LIMIT,
strokeWidth = this.strokeWidth > 1 ? this.strokeWidth : 0;
ctx.save();
@ -765,14 +770,14 @@
h = this.getHeight();
ctx.strokeRect(
~~(-(w / 2) - this.padding - this.strokeWidth / 2 * this.scaleX) + 0.5, // offset needed to make lines look sharper
~~(-(h / 2) - this.padding - this.strokeWidth / 2 * this.scaleY) + 0.5,
~~(w + padding2 + this.strokeWidth * this.scaleX),
~~(h + padding2 + this.strokeWidth * this.scaleY)
~~(-(w / 2) - this.padding - strokeWidth / 2 * this.scaleX) + 0.5, // offset needed to make lines look sharper
~~(-(h / 2) - this.padding - strokeWidth / 2 * this.scaleY) + 0.5,
~~(w + padding2 + strokeWidth * this.scaleX),
~~(h + padding2 + strokeWidth * this.scaleY)
);
if (this.hasRotatingPoint && !this.hideCorners && !this.lockRotation) {
var rotateHeight = (this.flipY ? h + this.strokeWidth * this.scaleY : -h - this.strokeWidth * this.scaleY) / 2;
var rotateHeight = (this.flipY ? h + strokeWidth * this.scaleY : -h - strokeWidth * this.scaleY) / 2;
var rotateWidth = (-w/2);
ctx.beginPath();

View file

@ -846,4 +846,25 @@
equal(isFired, true, 'removing active object should fire "selection:cleared"');
});
asyncTest('loadFromJSON with async content', function() {
var group = new fabric.Group([
new fabric.Rect({ width: 10, height: 20 }),
new fabric.Circle({ radius: 10 })
]);
var rect = new fabric.Rect({ width: 20, height: 10 });
var circle = new fabric.Circle({ radius: 25 });
canvas.add(group, rect, circle);
var json = JSON.stringify(canvas);
canvas.clear();
equal(0, canvas.getObjects().length);
canvas.loadFromJSON(json, function() {
equal(3, canvas.getObjects().length);
start();
});
});
})();

View file

@ -190,7 +190,7 @@
function testFractionDigits(fractionDigits, expectedValue) {
fabric.Object.prototype.NUM_FRACTION_DIGITS = fractionDigits;
fabric.Object.NUM_FRACTION_DIGITS = fractionDigits;
testedProperties.forEach(function(property) {
cObj.set(property, fractionalValue);
@ -198,7 +198,7 @@
'value of ' + property + ' should have ' + fractionDigits + ' fractional digits');
}, this);
fabric.Object.prototype.NUM_FRACTION_DIGITS = fractionDigitsDefault;
fabric.Object.NUM_FRACTION_DIGITS = fractionDigitsDefault;
}
testFractionDigits.call(this, 2, 166.67);