Fixed fabric.PathGroup.fromObject - use fabric.util.enlivenObjects to instatiate fabric.Path objects

Corrected jsdoc tags for fabric.PathGroup.fromObject, fabric.Path.fromObject and fabric.Path.fromElement
Fixed quint tests for fabric.Path and fabric.PathGroup
This commit is contained in:
Kienz 2013-07-18 22:21:19 +02:00
parent 6f1b6bf243
commit c9d866dcf9
4 changed files with 242 additions and 178 deletions

View file

@ -679,7 +679,8 @@
/**
* Creates an instance of fabric.Path from an object
* @static
* @return {fabric.Path} Instance of fabric.Path
* @param {Object} object
* @param {Function} callback Callback to invoke when an fabric.Path instance is created
*/
fabric.Path.fromObject = function(object, callback) {
if (typeof object.path === 'string') {
@ -712,8 +713,8 @@
* Creates an instance of fabric.Path from an SVG <path> element
* @static
* @param {SVGElement} element to parse
* @param {Function} callback Callback to invoke when an fabric.Path instance is created
* @param {Object} [options] Options object
* @return {fabric.Path} Instance of fabric.Path
*/
fabric.Path.fromElement = function(element, callback, options) {
var parsedAttributes = fabric.parseAttributes(element, fabric.Path.ATTRIBUTE_NAMES);

View file

@ -207,24 +207,11 @@
}
});
/**
* @private
*/
function instantiatePaths(paths) {
for (var i = 0, len = paths.length; i < len; i++) {
if (!(paths[i] instanceof fabric.Object)) {
var klassName = camelize(capitalize(paths[i].type));
paths[i] = fabric[klassName].fromObject(paths[i]);
}
}
return paths;
}
/**
* Creates fabric.PathGroup instance from an object representation
* @static
* @param {Object} object
* @return {fabric.PathGroup}
* @param {Function} callback Callback to invoke when an fabric.PathGroup instance is created
*/
fabric.PathGroup.fromObject = function(object, callback) {
if (typeof object.paths === 'string') {
@ -239,8 +226,10 @@
});
}
else {
var paths = instantiatePaths(object.paths);
callback(new fabric.PathGroup(paths, object));
fabric.util.enlivenObjects(object.paths, function(enlivenedObjects) {
delete object.paths;
callback(new fabric.PathGroup(enlivenedObjects, object));
});
}
};

View file

@ -47,63 +47,73 @@
return el;
}
function getPathObject(path) {
return fabric.Path.fromElement(getPathElement(path));
function getPathObject(path, callback) {
fabric.Path.fromElement(getPathElement(path), callback);
}
function makePathObject() {
return getPathObject("M 100 100 L 300 100 L 200 300 z");
function makePathObject(callback) {
getPathObject("M 100 100 L 300 100 L 200 300 z", callback);
}
QUnit.module('fabric.Path');
test('constructor', function() {
asyncTest('constructor', function() {
ok(fabric.Path);
var path = makePathObject();
ok(path instanceof fabric.Path);
ok(path instanceof fabric.Object);
makePathObject(function(path) {
ok(path instanceof fabric.Path);
ok(path instanceof fabric.Object);
equal(path.get('type'), 'path');
equal(path.get('type'), 'path');
var error;
try {
new fabric.Path();
}
catch(err) {
error = err;
}
var error;
try {
new fabric.Path();
}
catch(err) {
error = err;
}
ok(error, 'should throw error');
ok(error, 'should throw error');
start();
});
});
test('toString', function() {
var path = makePathObject();
ok(typeof path.toString == 'function');
equal(path.toString(), '#<fabric.Path (4): { "top": 200, "left": 200 }>');
asyncTest('toString', function() {
makePathObject(function(path) {
ok(typeof path.toString == 'function');
equal(path.toString(), '#<fabric.Path (4): { "top": 200, "left": 200 }>');
start();
});
});
test('toObject', function() {
var path = makePathObject();
ok(typeof path.toObject == 'function');
deepEqual(path.toObject(), REFERENCE_PATH_OBJECT);
asyncTest('toObject', function() {
makePathObject(function(path) {
ok(typeof path.toObject == 'function');
deepEqual(path.toObject(), REFERENCE_PATH_OBJECT);
start();
});
});
test('toDatalessObject', function() {
var path = makePathObject();
ok(typeof path.toDatalessObject == 'function');
deepEqual(path.toDatalessObject(), REFERENCE_PATH_OBJECT);
asyncTest('toDatalessObject', function() {
makePathObject(function(path) {
ok(typeof path.toDatalessObject == 'function');
deepEqual(path.toDatalessObject(), REFERENCE_PATH_OBJECT);
var src = 'http://example.com/';
path.setSourcePath(src);
deepEqual(path.toDatalessObject(), fabric.util.object.extend(fabric.util.object.clone(REFERENCE_PATH_OBJECT), {
var src = 'http://example.com/';
path.setSourcePath(src);
deepEqual(path.toDatalessObject(), fabric.util.object.extend(fabric.util.object.clone(REFERENCE_PATH_OBJECT), {
path: src
}));
}));
start();
});
});
test('complexity', function() {
var path = makePathObject();
ok(typeof path.complexity == 'function');
asyncTest('complexity', function() {
makePathObject(function(path) {
ok(typeof path.complexity == 'function');
start();
});
});
asyncTest('fromObject', function() {
@ -115,7 +125,7 @@
});
});
test('fromElement', function() {
asyncTest('fromElement', function() {
ok(typeof fabric.Path.fromElement == 'function');
var elPath = fabric.document.createElement('path');
@ -133,52 +143,59 @@
//elPath.setAttribute('transform', 'scale(2) translate(10, -20)');
elPath.setAttribute('transform', 'scale(2)');
var path = fabric.Path.fromElement(elPath);
ok(path instanceof fabric.Path);
fabric.Path.fromElement(elPath, function(path) {
ok(path instanceof fabric.Path);
deepEqual(path.toObject(), fabric.util.object.extend(REFERENCE_PATH_OBJECT, {
strokeDashArray: [5, 2],
strokeLineCap: 'round',
strokeLineJoin: 'bevil',
strokeMiterLimit: 5,
transformMatrix: [2, 0, 0, 2, 0, 0]
}));
deepEqual(path.toObject(), fabric.util.object.extend(REFERENCE_PATH_OBJECT, {
strokeDashArray: [5, 2],
strokeLineCap: 'round',
strokeLineJoin: 'bevil',
strokeMiterLimit: 5,
transformMatrix: [2, 0, 0, 2, 0, 0]
}));
var ANGLE = 90;
var ANGLE = 90;
elPath.setAttribute('transform', 'rotate(' + ANGLE + ')');
path = fabric.Path.fromElement(elPath);
elPath.setAttribute('transform', 'rotate(' + ANGLE + ')');
fabric.Path.fromElement(elPath, function(path) {
deepEqual(
path.get('transformMatrix'),
[ Math.cos(ANGLE), Math.sin(ANGLE), -Math.sin(ANGLE), Math.cos(ANGLE), 0, 0 ]
);
deepEqual(
path.get('transformMatrix'),
[ Math.cos(ANGLE), Math.sin(ANGLE), -Math.sin(ANGLE), Math.cos(ANGLE), 0, 0 ]
);
start();
});
});
});
test('multiple sequences in path commands', function() {
asyncTest('multiple sequences in path commands', function() {
var el = getPathElement('M100 100 l 200 200 300 300 400 -50 z');
var obj = fabric.Path.fromElement(el);
fabric.Path.fromElement(el, function(obj) {
deepEqual(obj.path[0], ['M', 100, 100]);
deepEqual(obj.path[1], ['l', 200, 200]);
deepEqual(obj.path[2], ['l', 300, 300]);
deepEqual(obj.path[3], ['l', 400, -50]);
deepEqual(obj.path[0], ['M', 100, 100]);
deepEqual(obj.path[1], ['l', 200, 200]);
deepEqual(obj.path[2], ['l', 300, 300]);
deepEqual(obj.path[3], ['l', 400, -50]);
el = getPathElement('c 0,-53.25604 43.17254,-96.42858 96.42857,-96.42857 53.25603,0 96.42857,43.17254 96.42857,96.42857');
obj = fabric.Path.fromElement(el);
el = getPathElement('c 0,-53.25604 43.17254,-96.42858 96.42857,-96.42857 53.25603,0 96.42857,43.17254 96.42857,96.42857');
fabric.Path.fromElement(el, function(obj) {
deepEqual(obj.path[0], ['c', 0, -53.25604, 43.17254, -96.42858, 96.42857, -96.42857]);
deepEqual(obj.path[1], ['c', 53.25603, 0, 96.42857, 43.17254, 96.42857, 96.42857]);
deepEqual(obj.path[0], ['c', 0, -53.25604, 43.17254, -96.42858, 96.42857, -96.42857]);
deepEqual(obj.path[1], ['c', 53.25603, 0, 96.42857, 43.17254, 96.42857, 96.42857]);
start();
});
});
});
test('compressed path commands', function() {
asyncTest('compressed path commands', function() {
var el = getPathElement('M56.224 84.12c-.047.132-.138.221-.322.215.046-.131.137-.221.322-.215z');
var obj = fabric.Path.fromElement(el);
fabric.Path.fromElement(el, function(obj) {
deepEqual(obj.path[0], ['M', 56.224, 84.12]);
deepEqual(obj.path[1], ['c', -0.047, 0.132, -0.138, 0.221, -0.322, 0.215]);
deepEqual(obj.path[2], ['c', 0.046, -0.131, 0.137, -0.221, 0.322, -0.215]);
deepEqual(obj.path[3], ['z']);
deepEqual(obj.path[0], ['M', 56.224, 84.12]);
deepEqual(obj.path[1], ['c', -0.047, 0.132, -0.138, 0.221, -0.322, 0.215]);
deepEqual(obj.path[2], ['c', 0.046, -0.131, 0.137, -0.221, 0.322, -0.215]);
deepEqual(obj.path[3], ['z']);
start();
});
});
})();

View file

@ -43,51 +43,76 @@
return el;
}
function getPathObject(path) {
return fabric.Path.fromElement(getPathElement(path));
function getPathObject(path, callback) {
fabric.Path.fromElement(getPathElement(path), callback);
}
function getPathObjects() {
return [getPathObject("M 100 100 L 300 100 L 200 300 z"),
getPathObject("M 200 200 L 100 200 L 400 50 z")];
function getPathObjects(callback) {
function onLoaded() {
if (++numLoadedObjects === numTotalObjects) {
if (callback) {
callback(objects);
}
}
}
var objects = [ ],
paths = ["M 100 100 L 300 100 L 200 300 z", "M 200 200 L 100 200 L 400 50 z"],
numLoadedObjects = 0,
numTotalObjects = paths.length;
paths.forEach(function (o, index) {
getPathObject(o, function(o) {
objects[index] = o;
onLoaded();
});
});
}
function getPathGroupObject() {
return new fabric.PathGroup(getPathObjects());
function getPathGroupObject(callback) {
getPathObjects(function(objects) {
callback(new fabric.PathGroup(objects));
})
}
QUnit.module('fabric.PathGroup');
test('constructor', function() {
asyncTest('constructor', function() {
ok(fabric.PathGroup);
var pathGroup = getPathGroupObject();
getPathGroupObject(function(pathGroup) {
ok(pathGroup instanceof fabric.PathGroup);
ok(pathGroup instanceof fabric.Object);
//this.assertHasMixin(Enumerable, pathGroup);
ok(pathGroup instanceof fabric.PathGroup);
ok(pathGroup instanceof fabric.Object);
//this.assertHasMixin(Enumerable, pathGroup);
equal(pathGroup.get('type'), 'path-group');
equal(pathGroup.get('type'), 'path-group');
start();
});
});
test('getObjects', function() {
var paths = getPathObjects();
var pathGroup = new fabric.PathGroup(paths);
ok(typeof pathGroup.getObjects == 'function');
asyncTest('getObjects', function() {
getPathObjects(function(paths) {
var pathGroup = new fabric.PathGroup(paths);
ok(typeof pathGroup.getObjects == 'function');
// nulling group to avoid circular reference (qUnit goes into inifinite loop)
paths[0].group = null;
paths[1].group = null;
// nulling group to avoid circular reference (qUnit goes into inifinite loop)
paths[0].group = null;
paths[1].group = null;
deepEqual(pathGroup.getObjects(), paths);
deepEqual(pathGroup.getObjects(), paths);
start();
});
});
test('toObject', function() {
var pathGroup = getPathGroupObject();
ok(typeof pathGroup.toObject == 'function');
var object = pathGroup.toObject();
asyncTest('toObject', function() {
getPathGroupObject(function(pathGroup) {
ok(typeof pathGroup.toObject == 'function');
var object = pathGroup.toObject();
start();
});
});
test('complexity', function() {
asyncTest('complexity', function() {
function sum(objects) {
var i = objects.length, total = 0;
while (i--) {
@ -95,100 +120,132 @@
}
return total;
}
var pathGroup = getPathGroupObject();
getPathGroupObject(function(pathGroup) {
ok(typeof pathGroup.complexity == 'function');
ok(typeof pathGroup.complexity == 'function');
var objectsTotalComplexity = pathGroup.getObjects().reduce(function(total, current) {
total += current.complexity();
return total;
}, 0);
var objectsTotalComplexity = pathGroup.getObjects().reduce(function(total, current) {
total += current.complexity();
return total;
}, 0);
equal(pathGroup.complexity(), objectsTotalComplexity);
});
test('toDatalessObject', function() {
var pathGroup = getPathGroupObject();
ok(typeof pathGroup.toDatalessObject == 'function');
pathGroup.setSourcePath('http://example.com/');
var expectedObject = fabric.util.object.extend(fabric.util.object.clone(REFERENCE_PATH_GROUP_OBJECT), {
'paths': 'http://example.com/',
'sourcePath': 'http://example.com/'
equal(pathGroup.complexity(), objectsTotalComplexity);
start();
});
deepEqual(pathGroup.toDatalessObject(), expectedObject);
});
test('toString', function() {
var pathGroup = getPathGroupObject();
ok(typeof pathGroup.toString == 'function');
equal(pathGroup.toString(), '#<fabric.PathGroup (8): { top: 0, left: 0 }>');
asyncTest('toDatalessObject', function() {
getPathGroupObject(function(pathGroup) {
ok(typeof pathGroup.toDatalessObject == 'function');
pathGroup.setSourcePath('http://example.com/');
var expectedObject = fabric.util.object.extend(fabric.util.object.clone(REFERENCE_PATH_GROUP_OBJECT), {
'paths': 'http://example.com/',
'sourcePath': 'http://example.com/'
});
deepEqual(pathGroup.toDatalessObject(), expectedObject);
start();
});
});
test('isSameColor', function() {
var pathGroup = getPathGroupObject();
asyncTest('fromObject', function() {
getPathGroupObject(function(pathGroup) {
ok(typeof pathGroup.isSameColor == 'function');
equal(pathGroup.isSameColor(), true);
ok(typeof fabric.PathGroup.fromObject == 'function');
var pathGroupObject = pathGroup.toObject();
pathGroup.getObjects()[0].set('fill', 'black');
equal(pathGroup.isSameColor(), false);
fabric.PathGroup.fromObject(pathGroupObject, function(newPathGroupFromObject) {
var objectFromOldPathGroup = pathGroup.toObject();
var objectFromNewPathGroup = newPathGroupFromObject.toObject();
ok(newPathGroupFromObject instanceof fabric.PathGroup);
deepEqual(objectFromNewPathGroup, objectFromOldPathGroup);
start();
});
});
});
test('set', function() {
asyncTest('toString', function() {
getPathGroupObject(function(pathGroup) {
ok(typeof pathGroup.toString == 'function');
equal(pathGroup.toString(), '#<fabric.PathGroup (8): { top: 0, left: 0 }>');
start();
});
});
asyncTest('isSameColor', function() {
getPathGroupObject(function(pathGroup) {
ok(typeof pathGroup.isSameColor == 'function');
equal(pathGroup.isSameColor(), true);
pathGroup.getObjects()[0].set('fill', 'black');
equal(pathGroup.isSameColor(), false);
start();
});
});
asyncTest('set', function() {
var fillValue = 'rgb(100,200,100)';
var pathGroup = getPathGroupObject();
getPathGroupObject(function(pathGroup) {
pathGroup.getObjects()[0].group = null;
pathGroup.getObjects()[1].group = null;
pathGroup.getObjects()[0].group = null;
pathGroup.getObjects()[1].group = null;
ok(typeof pathGroup.set == 'function');
equal(pathGroup.set('fill', fillValue), pathGroup, 'should be chainable');
ok(typeof pathGroup.set == 'function');
equal(pathGroup.set('fill', fillValue), pathGroup, 'should be chainable');
pathGroup.getObjects().forEach(function(path) {
equal(path.get('fill'), fillValue);
}, this);
pathGroup.getObjects().forEach(function(path) {
equal(path.get('fill'), fillValue);
}, this);
equal(pathGroup.get('fill'), fillValue);
equal(pathGroup.get('fill'), fillValue);
// set different color to one of the paths
pathGroup.getObjects()[1].set('fill', 'black');
pathGroup.set('fill', 'rgb(255,255,255)');
// set different color to one of the paths
pathGroup.getObjects()[1].set('fill', 'black');
pathGroup.set('fill', 'rgb(255,255,255)');
equal(pathGroup.getObjects()[0].get('fill'), 'rgb(100,200,100)',
'when paths are of different fill, setting fill of a group should not change them');
equal(pathGroup.getObjects()[0].get('fill'), 'rgb(100,200,100)',
'when paths are of different fill, setting fill of a group should not change them');
pathGroup.getObjects()[1].set('fill', 'red');
pathGroup.getObjects()[1].set('fill', 'red');
pathGroup.set('left', 1234);
ok(pathGroup.getObjects()[0].get('left') !== 1234);
equal(pathGroup.get('left'), 1234);
pathGroup.set('left', 1234);
ok(pathGroup.getObjects()[0].get('left') !== 1234);
equal(pathGroup.get('left'), 1234);
start();
});
});
test('grayscale', function() {
asyncTest('grayscale', function() {
var pathGroup = getPathGroupObject();
getPathGroupObject(function(pathGroup) {
pathGroup.getObjects()[0].group = null;
pathGroup.getObjects()[1].group = null;
pathGroup.getObjects()[0].group = null;
pathGroup.getObjects()[1].group = null;
ok(typeof pathGroup.toGrayscale == 'function');
equal(pathGroup.toGrayscale(), pathGroup, 'should be chainable');
var firstObject = pathGroup.getObjects()[0],
secondObject = pathGroup.getObjects()[1];
ok(typeof pathGroup.toGrayscale == 'function');
equal(pathGroup.toGrayscale(), pathGroup, 'should be chainable');
var firstObject = pathGroup.getObjects()[0],
secondObject = pathGroup.getObjects()[1];
firstObject.set('overlayFill', null);
secondObject.set('overlayFill', null);
firstObject.set('overlayFill', null);
secondObject.set('overlayFill', null);
firstObject.set('fill', 'rgb(200,0,0)');
secondObject.set('fill', '0000FF');
firstObject.set('fill', 'rgb(200,0,0)');
secondObject.set('fill', '0000FF');
pathGroup.toGrayscale();
pathGroup.toGrayscale();
equal(firstObject.get('overlayFill'), 'rgb(60,60,60)');
equal(secondObject.get('overlayFill'), 'rgb(28,28,28)');
equal(firstObject.get('overlayFill'), 'rgb(60,60,60)');
equal(secondObject.get('overlayFill'), 'rgb(28,28,28)');
equal(firstObject.get('fill'), 'rgb(200,0,0)', 'toGrayscale should not change original fill value');
equal(new fabric.Color(secondObject.get('fill')).toRgb(), 'rgb(0,0,255)', 'toGrayscale should not change original fill value');
equal(firstObject.get('fill'), 'rgb(200,0,0)', 'toGrayscale should not change original fill value');
equal(new fabric.Color(secondObject.get('fill')).toRgb(), 'rgb(0,0,255)', 'toGrayscale should not change original fill value');
start();
});
});
})();