2012-08-10 15:14:56 +00:00
|
|
|
(function(){
|
|
|
|
|
|
|
|
|
|
var REFERENCE_PATH_GROUP_OBJECT = {
|
2014-09-21 18:55:00 +00:00
|
|
|
'type': 'path-group',
|
|
|
|
|
'originX': 'left',
|
|
|
|
|
'originY': 'top',
|
|
|
|
|
'left': 0,
|
|
|
|
|
'top': 0,
|
|
|
|
|
'width': 0,
|
|
|
|
|
'height': 0,
|
|
|
|
|
'fill': '',
|
|
|
|
|
'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',
|
2015-04-23 09:47:23 +00:00
|
|
|
'globalCompositeOperation': 'source-over',
|
2015-07-19 23:28:38 +00:00
|
|
|
'transformMatrix': null,
|
2015-09-02 19:28:57 +00:00
|
|
|
'skewX': 0,
|
|
|
|
|
'skewY': 0,
|
2014-09-21 18:55:00 +00:00
|
|
|
'paths': getPathObjects()
|
2012-08-10 15:14:56 +00:00
|
|
|
};
|
|
|
|
|
|
2015-05-18 06:00:36 +00:00
|
|
|
var REFERENCE_PATH_GROUP_SVG = '<g style="stroke: none; stroke-width: 1; stroke-dasharray: none; stroke-linecap: butt; stroke-linejoin: miter; stroke-miterlimit: 10; fill: none; fill-rule: nonzero; opacity: 1;" transform="translate(0 0)" >\n' +
|
2015-07-27 10:21:27 +00:00
|
|
|
'\t<path d="M 100 100 L 300 100 L 200 300 z" style="stroke: blue; stroke-width: 3; stroke-dasharray: none; stroke-linecap: butt; stroke-linejoin: miter; stroke-miterlimit: 10; fill: rgb(255,0,0); fill-rule: nonzero; opacity: 1;" transform="" stroke-linecap="round" />\n' +
|
|
|
|
|
'\t<path d="M 200 200 L 100 200 L 400 50 z" style="stroke: blue; stroke-width: 3; stroke-dasharray: none; stroke-linecap: butt; stroke-linejoin: miter; stroke-miterlimit: 10; fill: rgb(255,0,0); fill-rule: nonzero; opacity: 1;" transform="" stroke-linecap="round" />\n' +
|
2015-01-28 08:13:52 +00:00
|
|
|
'</g>\n';
|
|
|
|
|
|
2015-05-18 06:00:36 +00:00
|
|
|
var REFERENCE_PATH_GROUP_SVG_WITH_MATRIX = '<g style="stroke: none; stroke-width: 1; stroke-dasharray: none; stroke-linecap: butt; stroke-linejoin: miter; stroke-miterlimit: 10; fill: none; fill-rule: nonzero; opacity: 1;" transform=" matrix(1 2 3 4 5 6) translate(0 0)" >\n' +
|
2015-07-27 10:21:27 +00:00
|
|
|
'\t<path d="M 100 100 L 300 100 L 200 300 z" style="stroke: blue; stroke-width: 3; stroke-dasharray: none; stroke-linecap: butt; stroke-linejoin: miter; stroke-miterlimit: 10; fill: rgb(255,0,0); fill-rule: nonzero; opacity: 1;" transform="" stroke-linecap="round" />\n' +
|
|
|
|
|
'\t<path d="M 200 200 L 100 200 L 400 50 z" style="stroke: blue; stroke-width: 3; stroke-dasharray: none; stroke-linecap: butt; stroke-linejoin: miter; stroke-miterlimit: 10; fill: rgb(255,0,0); fill-rule: nonzero; opacity: 1;" transform="" stroke-linecap="round" />\n' +
|
2015-01-28 08:13:52 +00:00
|
|
|
'</g>\n';
|
|
|
|
|
|
2012-08-10 15:14:56 +00:00
|
|
|
function getPathElement(path) {
|
|
|
|
|
var el = fabric.document.createElement('path');
|
|
|
|
|
el.setAttribute('d', path);
|
|
|
|
|
el.setAttribute('fill', 'rgb(255,0,0)');
|
|
|
|
|
el.setAttribute('stroke', 'blue');
|
Parse SVG stroke-opacity and fill-opacity
- SVG attribute opacity is now used for object's opacity
- fill-opacity and stroke-opacity are added to stroke and fill color value
- Add hsl/hsla support (e.g. hsl(270, 80%, 10%), hsla(320, 10%, 66%, 0.5))
- Add support for rgb/rgba values with whitespaces around values (e.g. rgba( 255 , 100 , 50 , 0.1 )) and percentage values (e.g. rgb(100%, 67%, 15%, 0.8))
- Delete stroke and strokeWidth from fabric.Text (defined in fabric.Object)
- New unit test for parse stroke-opacity and fill-opacity
- Update unit tests (new tests for hsl/hsla and rgb/rgba (whitespaces and percentage values))
- Change equal and deepEqual parameter order (e.g. equal(actualValue, expectedValue, message))
- Doc additions
2013-05-25 09:03:09 +00:00
|
|
|
el.setAttribute('stroke-width', 3);
|
2012-08-10 15:14:56 +00:00
|
|
|
return el;
|
|
|
|
|
}
|
|
|
|
|
|
2013-07-18 20:21:19 +00:00
|
|
|
function getPathObject(path, callback) {
|
|
|
|
|
fabric.Path.fromElement(getPathElement(path), callback);
|
2012-08-10 15:14:56 +00:00
|
|
|
}
|
|
|
|
|
|
2013-07-18 20:21:19 +00:00
|
|
|
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();
|
|
|
|
|
});
|
|
|
|
|
});
|
2012-08-10 15:14:56 +00:00
|
|
|
}
|
|
|
|
|
|
2015-07-17 10:25:17 +00:00
|
|
|
function getPathGroupObject(callback, options) {
|
|
|
|
|
options = options || { };
|
2013-07-18 20:21:19 +00:00
|
|
|
getPathObjects(function(objects) {
|
2015-07-17 10:25:17 +00:00
|
|
|
callback(new fabric.PathGroup(objects, options));
|
2014-04-14 16:17:06 +00:00
|
|
|
});
|
2012-08-10 15:14:56 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
QUnit.module('fabric.PathGroup');
|
|
|
|
|
|
2013-07-18 20:21:19 +00:00
|
|
|
asyncTest('constructor', function() {
|
2012-08-10 15:14:56 +00:00
|
|
|
ok(fabric.PathGroup);
|
2013-07-18 20:21:19 +00:00
|
|
|
getPathGroupObject(function(pathGroup) {
|
2012-08-10 15:14:56 +00:00
|
|
|
|
2013-07-18 20:21:19 +00:00
|
|
|
ok(pathGroup instanceof fabric.PathGroup);
|
|
|
|
|
ok(pathGroup instanceof fabric.Object);
|
|
|
|
|
//this.assertHasMixin(Enumerable, pathGroup);
|
2012-08-10 15:14:56 +00:00
|
|
|
|
2013-07-18 20:21:19 +00:00
|
|
|
equal(pathGroup.get('type'), 'path-group');
|
|
|
|
|
start();
|
|
|
|
|
});
|
2012-08-10 15:14:56 +00:00
|
|
|
});
|
|
|
|
|
|
2015-07-17 10:25:17 +00:00
|
|
|
asyncTest('parsingDmensions', function() {
|
|
|
|
|
|
|
|
|
|
getPathGroupObject(function(pathGroup) {
|
|
|
|
|
|
|
|
|
|
ok(pathGroup instanceof fabric.PathGroup);
|
|
|
|
|
ok(pathGroup instanceof fabric.Object);
|
|
|
|
|
//this.assertHasMixin(Enumerable, pathGroup);
|
|
|
|
|
equal(pathGroup.get('type'), 'path-group');
|
|
|
|
|
equal(pathGroup.width, 403);
|
|
|
|
|
equal(pathGroup.height, 303);
|
|
|
|
|
start();
|
|
|
|
|
}, {toBeParsed: true});
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
test('parsingDmensionsWithTransformMatrix', function() {
|
|
|
|
|
var pathA = new fabric.Path("M 100 100 L 300 100 L 200 300 z", {transformMatrix: [2, 0, 0, 2, 0, 0]}),
|
|
|
|
|
pathB = new fabric.Path("M 200 200 L 100 200 L 400 50 z", {transformMatrix: [3, 0, 0, 3, 0, 0]}),
|
|
|
|
|
pg = new fabric.PathGroup([pathA, pathB], {toBeParsed: true});
|
|
|
|
|
equal(pg.width, 1203);
|
|
|
|
|
equal(pg.height, 603);
|
|
|
|
|
});
|
|
|
|
|
|
2013-07-18 20:21:19 +00:00
|
|
|
asyncTest('getObjects', function() {
|
|
|
|
|
getPathObjects(function(paths) {
|
|
|
|
|
var pathGroup = new fabric.PathGroup(paths);
|
|
|
|
|
ok(typeof pathGroup.getObjects == 'function');
|
2012-08-10 15:14:56 +00:00
|
|
|
|
2013-07-18 20:21:19 +00:00
|
|
|
// nulling group to avoid circular reference (qUnit goes into inifinite loop)
|
|
|
|
|
paths[0].group = null;
|
|
|
|
|
paths[1].group = null;
|
2012-08-10 15:14:56 +00:00
|
|
|
|
2013-07-18 20:21:19 +00:00
|
|
|
deepEqual(pathGroup.getObjects(), paths);
|
|
|
|
|
start();
|
|
|
|
|
});
|
2012-08-10 15:14:56 +00:00
|
|
|
});
|
|
|
|
|
|
2013-07-18 20:21:19 +00:00
|
|
|
asyncTest('toObject', function() {
|
|
|
|
|
getPathGroupObject(function(pathGroup) {
|
|
|
|
|
ok(typeof pathGroup.toObject == 'function');
|
2015-04-23 09:47:23 +00:00
|
|
|
|
2013-07-18 20:21:19 +00:00
|
|
|
var object = pathGroup.toObject();
|
2015-04-23 09:47:23 +00:00
|
|
|
ok(typeof object == 'object');
|
|
|
|
|
|
2013-07-18 20:21:19 +00:00
|
|
|
start();
|
|
|
|
|
});
|
2012-08-10 15:14:56 +00:00
|
|
|
});
|
|
|
|
|
|
2013-07-18 20:21:19 +00:00
|
|
|
asyncTest('complexity', function() {
|
|
|
|
|
getPathGroupObject(function(pathGroup) {
|
2012-08-10 15:14:56 +00:00
|
|
|
|
2013-07-18 20:21:19 +00:00
|
|
|
ok(typeof pathGroup.complexity == 'function');
|
2012-08-10 15:14:56 +00:00
|
|
|
|
2013-07-18 20:21:19 +00:00
|
|
|
var objectsTotalComplexity = pathGroup.getObjects().reduce(function(total, current) {
|
|
|
|
|
total += current.complexity();
|
|
|
|
|
return total;
|
|
|
|
|
}, 0);
|
|
|
|
|
|
|
|
|
|
equal(pathGroup.complexity(), objectsTotalComplexity);
|
|
|
|
|
start();
|
|
|
|
|
});
|
|
|
|
|
});
|
2012-08-10 15:14:56 +00:00
|
|
|
|
2013-07-18 20:21:19 +00:00
|
|
|
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();
|
|
|
|
|
});
|
2012-08-10 15:14:56 +00:00
|
|
|
});
|
|
|
|
|
|
2013-07-18 20:21:19 +00:00
|
|
|
asyncTest('fromObject', function() {
|
|
|
|
|
getPathGroupObject(function(pathGroup) {
|
|
|
|
|
|
|
|
|
|
ok(typeof fabric.PathGroup.fromObject == 'function');
|
|
|
|
|
var pathGroupObject = pathGroup.toObject();
|
|
|
|
|
|
|
|
|
|
fabric.PathGroup.fromObject(pathGroupObject, function(newPathGroupFromObject) {
|
|
|
|
|
|
|
|
|
|
var objectFromOldPathGroup = pathGroup.toObject();
|
|
|
|
|
var objectFromNewPathGroup = newPathGroupFromObject.toObject();
|
|
|
|
|
|
|
|
|
|
ok(newPathGroupFromObject instanceof fabric.PathGroup);
|
2012-08-10 15:14:56 +00:00
|
|
|
|
2013-07-18 20:21:19 +00:00
|
|
|
deepEqual(objectFromNewPathGroup, objectFromOldPathGroup);
|
|
|
|
|
|
|
|
|
|
start();
|
|
|
|
|
});
|
2012-08-10 15:14:56 +00:00
|
|
|
});
|
|
|
|
|
});
|
|
|
|
|
|
2013-07-18 20:21:19 +00:00
|
|
|
asyncTest('toString', function() {
|
|
|
|
|
getPathGroupObject(function(pathGroup) {
|
|
|
|
|
ok(typeof pathGroup.toString == 'function');
|
|
|
|
|
equal(pathGroup.toString(), '#<fabric.PathGroup (8): { top: 0, left: 0 }>');
|
|
|
|
|
start();
|
|
|
|
|
});
|
2012-08-10 15:14:56 +00:00
|
|
|
});
|
|
|
|
|
|
2013-07-18 20:21:19 +00:00
|
|
|
asyncTest('isSameColor', function() {
|
|
|
|
|
getPathGroupObject(function(pathGroup) {
|
2012-08-10 15:14:56 +00:00
|
|
|
|
2013-07-18 20:21:19 +00:00
|
|
|
ok(typeof pathGroup.isSameColor == 'function');
|
|
|
|
|
equal(pathGroup.isSameColor(), true);
|
2012-08-10 15:14:56 +00:00
|
|
|
|
2013-07-18 20:21:19 +00:00
|
|
|
pathGroup.getObjects()[0].set('fill', 'black');
|
|
|
|
|
equal(pathGroup.isSameColor(), false);
|
2014-04-14 16:17:06 +00:00
|
|
|
|
|
|
|
|
// case
|
|
|
|
|
pathGroup.getObjects()[0].set('fill', '#ff5555');
|
|
|
|
|
pathGroup.getObjects()[1].set('fill', '#FF5555');
|
|
|
|
|
equal(pathGroup.isSameColor(), true);
|
|
|
|
|
|
2013-07-18 20:21:19 +00:00
|
|
|
start();
|
|
|
|
|
});
|
2012-08-10 15:14:56 +00:00
|
|
|
});
|
|
|
|
|
|
2013-07-18 20:21:19 +00:00
|
|
|
asyncTest('set', function() {
|
2012-08-10 15:14:56 +00:00
|
|
|
var fillValue = 'rgb(100,200,100)';
|
2013-07-18 20:21:19 +00:00
|
|
|
getPathGroupObject(function(pathGroup) {
|
2012-08-10 15:14:56 +00:00
|
|
|
|
2013-07-18 20:21:19 +00:00
|
|
|
pathGroup.getObjects()[0].group = null;
|
|
|
|
|
pathGroup.getObjects()[1].group = null;
|
2012-08-10 15:14:56 +00:00
|
|
|
|
2013-07-18 20:21:19 +00:00
|
|
|
ok(typeof pathGroup.set == 'function');
|
|
|
|
|
equal(pathGroup.set('fill', fillValue), pathGroup, 'should be chainable');
|
2012-08-10 15:14:56 +00:00
|
|
|
|
2013-07-18 20:21:19 +00:00
|
|
|
pathGroup.getObjects().forEach(function(path) {
|
|
|
|
|
equal(path.get('fill'), fillValue);
|
|
|
|
|
}, this);
|
2012-08-10 15:14:56 +00:00
|
|
|
|
2013-07-18 20:21:19 +00:00
|
|
|
equal(pathGroup.get('fill'), fillValue);
|
2012-08-10 15:14:56 +00:00
|
|
|
|
2013-07-18 20:21:19 +00:00
|
|
|
// set different color to one of the paths
|
|
|
|
|
pathGroup.getObjects()[1].set('fill', 'black');
|
|
|
|
|
pathGroup.set('fill', 'rgb(255,255,255)');
|
2012-08-10 15:14:56 +00:00
|
|
|
|
2013-07-18 20:21:19 +00:00
|
|
|
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');
|
2012-08-10 15:14:56 +00:00
|
|
|
|
2013-07-18 20:21:19 +00:00
|
|
|
pathGroup.getObjects()[1].set('fill', 'red');
|
2012-08-10 15:14:56 +00:00
|
|
|
|
2013-07-18 20:21:19 +00:00
|
|
|
pathGroup.set('left', 1234);
|
|
|
|
|
ok(pathGroup.getObjects()[0].get('left') !== 1234);
|
|
|
|
|
equal(pathGroup.get('left'), 1234);
|
|
|
|
|
start();
|
|
|
|
|
});
|
2012-08-10 15:14:56 +00:00
|
|
|
});
|
2015-04-23 09:47:23 +00:00
|
|
|
|
2015-01-28 08:13:52 +00:00
|
|
|
asyncTest('toSVG', function() {
|
|
|
|
|
ok(fabric.PathGroup);
|
|
|
|
|
getPathGroupObject(function(pathGroup) {
|
|
|
|
|
ok(typeof pathGroup.toSVG == 'function');
|
|
|
|
|
equal(pathGroup.toSVG(), REFERENCE_PATH_GROUP_SVG);
|
|
|
|
|
pathGroup.transformMatrix = [1, 2, 3, 4, 5, 6];
|
|
|
|
|
equal(pathGroup.toSVG(), REFERENCE_PATH_GROUP_SVG_WITH_MATRIX);
|
|
|
|
|
start();
|
|
|
|
|
});
|
|
|
|
|
});
|
2015-03-01 18:21:10 +00:00
|
|
|
|
|
|
|
|
asyncTest('toSVGCenterOrigin', function() {
|
|
|
|
|
ok(fabric.PathGroup);
|
|
|
|
|
getPathGroupObject(function(pathGroup) {
|
|
|
|
|
ok(typeof pathGroup.toSVG == 'function');
|
2015-04-28 02:27:00 +00:00
|
|
|
pathGroup.strokeWidth = 0;
|
2015-03-01 18:21:10 +00:00
|
|
|
pathGroup.originX = 'center';
|
|
|
|
|
pathGroup.originY = 'center';
|
|
|
|
|
pathGroup.width = 700;
|
|
|
|
|
pathGroup.height = 600;
|
|
|
|
|
pathGroup.left = 350;
|
|
|
|
|
pathGroup.top = 300;
|
2015-04-28 02:27:00 +00:00
|
|
|
equal(pathGroup.toSVG(), REFERENCE_PATH_GROUP_SVG.replace('stroke-width: 1', 'stroke-width: 0'));
|
2015-03-01 18:21:10 +00:00
|
|
|
start();
|
|
|
|
|
});
|
2015-04-23 09:47:23 +00:00
|
|
|
});
|
2013-06-02 21:04:54 +00:00
|
|
|
})();
|