mirror of
https://github.com/Hopiu/fabric.js.git
synced 2026-03-16 22:10:32 +00:00
ClipPath to svg (#5234)
* svg plain examples works * more code reuse in visual tests
This commit is contained in:
parent
513233bf78
commit
ffe01ab9f6
10 changed files with 245 additions and 374 deletions
|
|
@ -75,7 +75,7 @@ jobs:
|
||||||
- stage: Unit Tests
|
- stage: Unit Tests
|
||||||
node_js: "4"
|
node_js: "4"
|
||||||
- stage: Visual Tests
|
- stage: Visual Tests
|
||||||
env: LAUNCHER=Node CANFAIL=TRUE
|
env: LAUNCHER=Node
|
||||||
node_js: "8"
|
node_js: "8"
|
||||||
script: npm run build:fast && npm run test:visual
|
script: npm run build:fast && npm run test:visual
|
||||||
- stage: Visual Tests
|
- stage: Visual Tests
|
||||||
|
|
|
||||||
|
|
@ -53,7 +53,7 @@
|
||||||
"lint": "eslint --config .eslintrc.json src",
|
"lint": "eslint --config .eslintrc.json src",
|
||||||
"lint_tests": "eslint test/unit --config .eslintrc_tests && eslint test/visual --config .eslintrc_tests",
|
"lint_tests": "eslint test/unit --config .eslintrc_tests && eslint test/visual --config .eslintrc_tests",
|
||||||
"export_dist_to_site": "cp dist/fabric.js ../fabricjs.com/lib/fabric.js && cp package.json ../fabricjs.com/lib/package.json && cp -r src HEADER.js lib ../fabricjs.com/build/files/",
|
"export_dist_to_site": "cp dist/fabric.js ../fabricjs.com/lib/fabric.js && cp package.json ../fabricjs.com/lib/package.json && cp -r src HEADER.js lib ../fabricjs.com/build/files/",
|
||||||
"export_tests_to_site": "cp test/unit/*.js ../fabricjs.com/test/unit && cp -r test/visual/* ../fabricjs.com/test/visual && cp -r test/fixtures/* ../fabricjs.com/test/fixtures",
|
"export_tests_to_site": "cp test/unit/*.js ../fabricjs.com/test/unit && cp -r test/visual/* ../fabricjs.com/test/visual && cp -r test/fixtures/* ../fabricjs.com/test/fixtures && cp -r test/lib/* ../fabricjs.com/test/lib",
|
||||||
"all": "npm run build && npm run test && npm run test:visual && npm run lint && npm run lint_tests && npm run export_dist_to_site && npm run export_tests_to_site",
|
"all": "npm run build && npm run test && npm run test:visual && npm run lint && npm run lint_tests && npm run export_dist_to_site && npm run export_tests_to_site",
|
||||||
"testem": "testem .",
|
"testem": "testem .",
|
||||||
"testem:visual": "testem --file testem-visual.json",
|
"testem:visual": "testem --file testem-visual.json",
|
||||||
|
|
|
||||||
|
|
@ -99,7 +99,12 @@ fabric.ElementsParser = function(elements, callback, options, reviver, parsingOp
|
||||||
this.options
|
this.options
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
clipPath = new fabric.Group(container);
|
if (container.length === 1) {
|
||||||
|
clipPath = container[0];
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
clipPath = new fabric.Group(container);
|
||||||
|
}
|
||||||
gTransform = fabric.util.multiplyTransformMatrices(
|
gTransform = fabric.util.multiplyTransformMatrices(
|
||||||
objTransformInv,
|
objTransformInv,
|
||||||
clipPath.calcTransformMatrix()
|
clipPath.calcTransformMatrix()
|
||||||
|
|
|
||||||
|
|
@ -211,13 +211,9 @@
|
||||||
markup.push(this.shadow.toSVG(this));
|
markup.push(this.shadow.toSVG(this));
|
||||||
}
|
}
|
||||||
if (clipPath) {
|
if (clipPath) {
|
||||||
if (clipPath.clipPathId === undefined) {
|
clipPath.clipPathId = 'CLIPPATH_' + fabric.Object.__uid++;
|
||||||
clipPath.clipPathId = 'CLIPPATH_' + fabric.Object.__uid++;
|
|
||||||
}
|
|
||||||
markup.push(
|
markup.push(
|
||||||
'<clipPath id="' + clipPath.clipPathId + '" ',
|
'<clipPath id="' + clipPath.clipPathId + '" >\n\t',
|
||||||
'clipPathUnits="objectBoundingBox" ',
|
|
||||||
'transform="translate(' + (this.width / 2) + ' , ' + (this.height / 2) + ')" >\n\t',
|
|
||||||
this.clipPath.toSVG(),
|
this.clipPath.toSVG(),
|
||||||
'</clipPath>\n'
|
'</clipPath>\n'
|
||||||
);
|
);
|
||||||
|
|
|
||||||
149
test/lib/visualTestLoop.js
Normal file
149
test/lib/visualTestLoop.js
Normal file
|
|
@ -0,0 +1,149 @@
|
||||||
|
(function(exports) {
|
||||||
|
|
||||||
|
exports.getFixture = function(name, original, callback) {
|
||||||
|
getImage(getFixtureName(name), original, callback);
|
||||||
|
};
|
||||||
|
|
||||||
|
exports.getAsset = function(name, callback) {
|
||||||
|
var finalName = getAssetName(name);
|
||||||
|
if (fabric.isLikelyNode) {
|
||||||
|
return fs.readFile(finalName, { encoding: 'utf8' }, callback);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
fabric.util.request(finalName, {
|
||||||
|
onComplete: function(xhr) {
|
||||||
|
callback(null, xhr.responseText);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
function getAbsolutePath(path) {
|
||||||
|
var isAbsolute = /^https?:/.test(path);
|
||||||
|
if (isAbsolute) { return path; };
|
||||||
|
var imgEl = fabric.document.createElement('img');
|
||||||
|
imgEl.src = path;
|
||||||
|
var src = imgEl.src;
|
||||||
|
imgEl = null;
|
||||||
|
return src;
|
||||||
|
}
|
||||||
|
|
||||||
|
function getAssetName(filename) {
|
||||||
|
var finalName = '/assets/' + filename + '.svg';
|
||||||
|
return fabric.isLikelyNode ? (__dirname + '/../visual' + finalName) : getAbsolutePath('/test/visual' + finalName);
|
||||||
|
}
|
||||||
|
|
||||||
|
function getGoldeName(filename) {
|
||||||
|
var finalName = '/golden/' + filename;
|
||||||
|
return fabric.isLikelyNode ? (__dirname + '/../visual' + finalName) : getAbsolutePath('/test/visual' + finalName);
|
||||||
|
}
|
||||||
|
|
||||||
|
function getFixtureName(filename) {
|
||||||
|
var finalName = '/fixtures/' + filename;
|
||||||
|
return fabric.isLikelyNode ? (__dirname + '/..' + finalName) : getAbsolutePath('/test' + finalName);
|
||||||
|
}
|
||||||
|
|
||||||
|
function getImage(filename, original, callback) {
|
||||||
|
if (fabric.isLikelyNode && original) {
|
||||||
|
try {
|
||||||
|
fs.statSync(filename);
|
||||||
|
}
|
||||||
|
catch (err) {
|
||||||
|
var dataUrl = original.toDataURL().split(',')[1];
|
||||||
|
console.log('creating original for ', filename);
|
||||||
|
fs.writeFileSync(filename, dataUrl, { encoding: 'base64' });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
var img = fabric.document.createElement('img');
|
||||||
|
img.onload = function() {
|
||||||
|
img.onload = null;
|
||||||
|
callback(img);
|
||||||
|
};
|
||||||
|
img.onerror = function(err) {
|
||||||
|
img.onerror = null;
|
||||||
|
callback(img);
|
||||||
|
console.log('Image loading errored', err);
|
||||||
|
};
|
||||||
|
img.src = filename;
|
||||||
|
}
|
||||||
|
|
||||||
|
exports.visualTestLoop = function(fabricCanvas, QUnit) {
|
||||||
|
var _pixelMatch;
|
||||||
|
var visualCallback;
|
||||||
|
var imageDataToChalk;
|
||||||
|
if (fabric.isLikelyNode) {
|
||||||
|
_pixelMatch = global.pixelmatch;
|
||||||
|
visualCallback = global.visualCallback;
|
||||||
|
imageDataToChalk = global.imageDataToChalk;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
if (window) {
|
||||||
|
_pixelMatch = window.pixelmatch;
|
||||||
|
visualCallback = window.visualCallback;
|
||||||
|
}
|
||||||
|
imageDataToChalk = function() { return ''; };
|
||||||
|
}
|
||||||
|
|
||||||
|
var pixelmatchOptions = {
|
||||||
|
includeAA: false,
|
||||||
|
threshold: 0.095
|
||||||
|
};
|
||||||
|
|
||||||
|
function beforeEachHandler() {
|
||||||
|
fabricCanvas.clipPath = null;
|
||||||
|
fabricCanvas.viewportTransform = [1, 0, 0, 1, 0, 0];
|
||||||
|
fabricCanvas.clear();
|
||||||
|
fabricCanvas.renderAll();
|
||||||
|
}
|
||||||
|
|
||||||
|
return function testCallback(testObj) {
|
||||||
|
var testName = testObj.test;
|
||||||
|
var code = testObj.code;
|
||||||
|
var percentage = testObj.percentage;
|
||||||
|
var golden = testObj.golden;
|
||||||
|
var newModule = testObj.newModule;
|
||||||
|
if (newModule) {
|
||||||
|
QUnit.module(newModule, {
|
||||||
|
beforeEach: beforeEachHandler,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
QUnit.test(testName, function(assert) {
|
||||||
|
var done = assert.async();
|
||||||
|
code(fabricCanvas, function(renderedCanvas) {
|
||||||
|
var width = renderedCanvas.width;
|
||||||
|
var height = renderedCanvas.height;
|
||||||
|
var totalPixels = width * height;
|
||||||
|
var imageDataCanvas = renderedCanvas.getContext('2d').getImageData(0, 0, width, height).data;
|
||||||
|
var canvas = fabric.document.createElement('canvas');
|
||||||
|
canvas.width = width;
|
||||||
|
canvas.height = height;
|
||||||
|
var ctx = canvas.getContext('2d');
|
||||||
|
var output = ctx.getImageData(0, 0, width, height);
|
||||||
|
getImage(getGoldeName(golden), renderedCanvas, function(goldenImage) {
|
||||||
|
ctx.drawImage(goldenImage, 0, 0);
|
||||||
|
visualCallback.addArguments({
|
||||||
|
enabled: true,
|
||||||
|
golden: canvas,
|
||||||
|
fabric: renderedCanvas,
|
||||||
|
diff: output
|
||||||
|
});
|
||||||
|
var imageDataGolden = ctx.getImageData(0, 0, width, height).data;
|
||||||
|
var differentPixels = _pixelMatch(imageDataCanvas, imageDataGolden, output.data, width, height, pixelmatchOptions);
|
||||||
|
var percDiff = differentPixels / totalPixels * 100;
|
||||||
|
var okDiff = totalPixels * percentage;
|
||||||
|
var isOK = differentPixels < okDiff;
|
||||||
|
assert.ok(
|
||||||
|
isOK,
|
||||||
|
testName + ' has too many different pixels ' + differentPixels + '(' + okDiff + ') representing ' + percDiff + '%'
|
||||||
|
);
|
||||||
|
if (!isOK) {
|
||||||
|
var stringa = imageDataToChalk(output);
|
||||||
|
console.log(stringa);
|
||||||
|
}
|
||||||
|
done();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})(typeof window === 'undefined' ? exports : this);
|
||||||
|
|
@ -6,10 +6,13 @@ global.fs = require('fs');
|
||||||
global.visualCallback = {
|
global.visualCallback = {
|
||||||
addArguments: function() {},
|
addArguments: function() {},
|
||||||
};
|
};
|
||||||
|
global.visualTestLoop = require('./lib/visualTestLoop').visualTestLoop;
|
||||||
|
global.getFixture = require('./lib/visualTestLoop').getFixture;
|
||||||
|
global.getAsset = require('./lib/visualTestLoop').getAsset;
|
||||||
global.imageDataToChalk = function(imageData) {
|
global.imageDataToChalk = function(imageData) {
|
||||||
// actually this does not work on travis-ci, so commenting it out
|
// actually this does not work on travis-ci, so commenting it out
|
||||||
return '';
|
return '';
|
||||||
var block = String.fromCharCode(9608)
|
var block = String.fromCharCode(9608);
|
||||||
var data = imageData.data;
|
var data = imageData.data;
|
||||||
var width = imageData.width;
|
var width = imageData.width;
|
||||||
var height = imageData.height;
|
var height = imageData.height;
|
||||||
|
|
|
||||||
|
|
@ -2,82 +2,22 @@
|
||||||
fabric.enableGLFiltering = false;
|
fabric.enableGLFiltering = false;
|
||||||
fabric.isWebglSupported = false;
|
fabric.isWebglSupported = false;
|
||||||
fabric.Object.prototype.objectCaching = true;
|
fabric.Object.prototype.objectCaching = true;
|
||||||
var _pixelMatch;
|
var visualTestLoop;
|
||||||
var visualCallback;
|
|
||||||
var fs;
|
|
||||||
var imageDataToChalk;
|
|
||||||
if (fabric.isLikelyNode) {
|
if (fabric.isLikelyNode) {
|
||||||
fs = global.fs;
|
visualTestLoop = global.visualTestLoop;
|
||||||
_pixelMatch = global.pixelmatch;
|
|
||||||
visualCallback = global.visualCallback;
|
|
||||||
imageDataToChalk = global.imageDataToChalk;
|
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
_pixelMatch = pixelmatch;
|
visualTestLoop = window.visualTestLoop;
|
||||||
if (window) {
|
|
||||||
visualCallback = window.visualCallback;
|
|
||||||
}
|
|
||||||
imageDataToChalk = function() { return ''; };
|
|
||||||
}
|
}
|
||||||
var fabricCanvas = this.canvas = new fabric.Canvas(null, {
|
var fabricCanvas = this.canvas = new fabric.Canvas(null, {
|
||||||
enableRetinaScaling: false, renderOnAddRemove: false, width: 200, height: 200,
|
enableRetinaScaling: false, renderOnAddRemove: false, width: 200, height: 200,
|
||||||
});
|
});
|
||||||
var pixelmatchOptions = {
|
|
||||||
includeAA: false,
|
|
||||||
threshold: 0.095
|
|
||||||
};
|
|
||||||
|
|
||||||
function getAbsolutePath(path) {
|
|
||||||
var isAbsolute = /^https?:/.test(path);
|
|
||||||
if (isAbsolute) { return path; };
|
|
||||||
var imgEl = fabric.document.createElement('img');
|
|
||||||
imgEl.src = path;
|
|
||||||
var src = imgEl.src;
|
|
||||||
imgEl = null;
|
|
||||||
return src;
|
|
||||||
}
|
|
||||||
|
|
||||||
// function getFixtureName(filename) {
|
// function getFixtureName(filename) {
|
||||||
// var finalName = '/fixtures/' + filename;
|
// var finalName = '/fixtures/' + filename;
|
||||||
// return fabric.isLikelyNode ? (__dirname + '/..' + finalName) : getAbsolutePath('/test' + finalName);
|
// return fabric.isLikelyNode ? (__dirname + '/..' + finalName) : getAbsolutePath('/test' + finalName);
|
||||||
// }
|
// }
|
||||||
|
|
||||||
function getGoldeName(filename) {
|
|
||||||
var finalName = '/golden/' + filename;
|
|
||||||
return fabric.isLikelyNode ? (__dirname + finalName) : getAbsolutePath('/test/visual' + finalName);
|
|
||||||
}
|
|
||||||
|
|
||||||
function getImage(filename, original, callback) {
|
|
||||||
if (fabric.isLikelyNode && original) {
|
|
||||||
try {
|
|
||||||
fs.statSync(filename);
|
|
||||||
}
|
|
||||||
catch (err) {
|
|
||||||
var dataUrl = original.toDataURL().split(',')[1];
|
|
||||||
console.log('creating original for ', filename);
|
|
||||||
fs.writeFileSync(filename, dataUrl, { encoding: 'base64' });
|
|
||||||
}
|
|
||||||
}
|
|
||||||
var img = fabric.document.createElement('img');
|
|
||||||
img.onload = function() {
|
|
||||||
img.onload = null;
|
|
||||||
callback(img);
|
|
||||||
};
|
|
||||||
img.onerror = function(err) {
|
|
||||||
img.onerror = null;
|
|
||||||
callback(img);
|
|
||||||
console.log('Image loading errored', err);
|
|
||||||
};
|
|
||||||
img.src = filename;
|
|
||||||
}
|
|
||||||
|
|
||||||
function beforeEachHandler() {
|
|
||||||
fabricCanvas.clipPath = null;
|
|
||||||
fabricCanvas.viewportTransform = [1, 0, 0, 1, 0, 0];
|
|
||||||
fabricCanvas.clear();
|
|
||||||
fabricCanvas.renderAll();
|
|
||||||
}
|
|
||||||
|
|
||||||
var tests = [];
|
var tests = [];
|
||||||
|
|
||||||
function clipping0(canvas, callback) {
|
function clipping0(canvas, callback) {
|
||||||
|
|
@ -365,54 +305,5 @@
|
||||||
percentage: 0.06,
|
percentage: 0.06,
|
||||||
});
|
});
|
||||||
|
|
||||||
|
tests.forEach(visualTestLoop(fabricCanvas, QUnit));
|
||||||
tests.forEach(function(testObj) {
|
|
||||||
var testName = testObj.test;
|
|
||||||
var code = testObj.code;
|
|
||||||
var percentage = testObj.percentage;
|
|
||||||
var golden = testObj.golden;
|
|
||||||
var newModule = testObj.newModule;
|
|
||||||
if (newModule) {
|
|
||||||
QUnit.module(newModule, {
|
|
||||||
beforeEach: beforeEachHandler,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
QUnit.test(testName, function(assert) {
|
|
||||||
var done = assert.async();
|
|
||||||
code(fabricCanvas, function(renderedCanvas) {
|
|
||||||
var width = renderedCanvas.width;
|
|
||||||
var height = renderedCanvas.height;
|
|
||||||
var totalPixels = width * height;
|
|
||||||
var imageDataCanvas = renderedCanvas.getContext('2d').getImageData(0, 0, width, height).data;
|
|
||||||
var canvas = fabric.document.createElement('canvas');
|
|
||||||
canvas.width = width;
|
|
||||||
canvas.height = height;
|
|
||||||
var ctx = canvas.getContext('2d');
|
|
||||||
var output = ctx.getImageData(0, 0, width, height);
|
|
||||||
getImage(getGoldeName(golden), renderedCanvas, function(goldenImage) {
|
|
||||||
ctx.drawImage(goldenImage, 0, 0);
|
|
||||||
visualCallback.addArguments({
|
|
||||||
enabled: true,
|
|
||||||
golden: canvas,
|
|
||||||
fabric: renderedCanvas,
|
|
||||||
diff: output
|
|
||||||
});
|
|
||||||
var imageDataGolden = ctx.getImageData(0, 0, width, height).data;
|
|
||||||
var differentPixels = _pixelMatch(imageDataCanvas, imageDataGolden, output.data, width, height, pixelmatchOptions);
|
|
||||||
var percDiff = differentPixels / totalPixels * 100;
|
|
||||||
var okDiff = totalPixels * percentage;
|
|
||||||
var isOK = differentPixels < okDiff;
|
|
||||||
assert.ok(
|
|
||||||
isOK,
|
|
||||||
testName + ' has too many different pixels ' + differentPixels + '(' + okDiff + ') representing ' + percDiff + '%'
|
|
||||||
);
|
|
||||||
if (!isOK) {
|
|
||||||
var stringa = imageDataToChalk(output);
|
|
||||||
console.log(stringa);
|
|
||||||
}
|
|
||||||
done();
|
|
||||||
});
|
|
||||||
});
|
|
||||||
});
|
|
||||||
});
|
|
||||||
})();
|
})();
|
||||||
|
|
|
||||||
|
|
@ -1,84 +1,23 @@
|
||||||
(function() {
|
(function() {
|
||||||
fabric.enableGLFiltering = false;
|
fabric.enableGLFiltering = false;
|
||||||
fabric.isWebglSupported = false;
|
fabric.isWebglSupported = false;
|
||||||
var _pixelMatch;
|
fabric.Object.prototype.objectCaching = false;
|
||||||
var visualCallback;
|
var visualTestLoop;
|
||||||
var fs;
|
var getFixture;
|
||||||
if (fabric.isLikelyNode) {
|
if (fabric.isLikelyNode) {
|
||||||
fs = global.fs;
|
visualTestLoop = global.visualTestLoop;
|
||||||
_pixelMatch = global.pixelmatch;
|
getFixture = global.getFixture;
|
||||||
visualCallback = global.visualCallback;
|
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
_pixelMatch = pixelmatch;
|
visualTestLoop = window.visualTestLoop;
|
||||||
if (window) {
|
getFixture = window.getFixture;
|
||||||
visualCallback = window.visualCallback;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
var fabricCanvas = this.canvas = new fabric.Canvas(null, {enableRetinaScaling: false, renderOnAddRemove: false});
|
var fabricCanvas = this.canvas = new fabric.Canvas(null, {enableRetinaScaling: false, renderOnAddRemove: false});
|
||||||
var pixelmatchOptions = {
|
|
||||||
includeAA: false,
|
|
||||||
threshold: 0.095
|
|
||||||
};
|
|
||||||
fabric.Object.prototype.objectCaching = false;
|
|
||||||
|
|
||||||
function getAbsolutePath(path) {
|
|
||||||
var isAbsolute = /^https?:/.test(path);
|
|
||||||
if (isAbsolute) { return path; };
|
|
||||||
var imgEl = fabric.document.createElement('img');
|
|
||||||
imgEl.src = path;
|
|
||||||
var src = imgEl.src;
|
|
||||||
imgEl = null;
|
|
||||||
return src;
|
|
||||||
}
|
|
||||||
|
|
||||||
function getFixtureName(filename) {
|
|
||||||
var finalName = '/fixtures/' + filename;
|
|
||||||
return fabric.isLikelyNode ? (__dirname + '/..' + finalName) : getAbsolutePath('/test' + finalName);
|
|
||||||
}
|
|
||||||
|
|
||||||
function getGoldeName(filename) {
|
|
||||||
var finalName = '/golden/' + filename;
|
|
||||||
return fabric.isLikelyNode ? (__dirname + finalName) : getAbsolutePath('/test/visual' + finalName);
|
|
||||||
}
|
|
||||||
|
|
||||||
function getImage(filename, original, callback) {
|
|
||||||
if (fabric.isLikelyNode && original) {
|
|
||||||
try {
|
|
||||||
fs.statSync(filename);
|
|
||||||
}
|
|
||||||
catch (err) {
|
|
||||||
var dataUrl = original.toDataURL().split(',')[1];
|
|
||||||
console.log('creating original for ', filename);
|
|
||||||
fs.writeFileSync(filename, dataUrl, { encoding: 'base64' });
|
|
||||||
}
|
|
||||||
}
|
|
||||||
var img = fabric.document.createElement('img');
|
|
||||||
img.onload = function() {
|
|
||||||
img.onload = null;
|
|
||||||
callback(img);
|
|
||||||
};
|
|
||||||
img.onerror = function(err) {
|
|
||||||
img.onerror = null;
|
|
||||||
console.log('Image loading errored', err);
|
|
||||||
};
|
|
||||||
img.src = filename;
|
|
||||||
}
|
|
||||||
|
|
||||||
function beforeEachHandler() {
|
|
||||||
fabricCanvas.setZoom(1);
|
|
||||||
fabricCanvas.setDimensions({
|
|
||||||
width: 300,
|
|
||||||
height: 150,
|
|
||||||
});
|
|
||||||
fabricCanvas.clear();
|
|
||||||
fabricCanvas.renderAll();
|
|
||||||
}
|
|
||||||
|
|
||||||
var tests = [];
|
var tests = [];
|
||||||
|
|
||||||
function imageResizeTest(canvas, callback) {
|
function imageResizeTest(canvas, callback) {
|
||||||
getImage(getFixtureName('parrot.png'), false, function(img) {
|
getFixture('parrot.png', false, function(img) {
|
||||||
canvas.setDimensions({
|
canvas.setDimensions({
|
||||||
width: 200,
|
width: 200,
|
||||||
height: 200,
|
height: 200,
|
||||||
|
|
@ -100,11 +39,11 @@
|
||||||
code: imageResizeTest,
|
code: imageResizeTest,
|
||||||
golden: 'parrot.png',
|
golden: 'parrot.png',
|
||||||
newModule: 'Image resize filter test',
|
newModule: 'Image resize filter test',
|
||||||
percentage: 0.06,
|
percentage: 0.08,
|
||||||
});
|
});
|
||||||
|
|
||||||
function imageResizeTestNoZoom(canvas, callback) {
|
function imageResizeTestNoZoom(canvas, callback) {
|
||||||
getImage(getFixtureName('parrot.png'), false, function(img) {
|
getFixture('parrot.png', false, function(img) {
|
||||||
canvas.setDimensions({
|
canvas.setDimensions({
|
||||||
width: 200,
|
width: 200,
|
||||||
height: 200,
|
height: 200,
|
||||||
|
|
@ -123,11 +62,11 @@
|
||||||
test: 'Image resize without zoom',
|
test: 'Image resize without zoom',
|
||||||
code: imageResizeTestNoZoom,
|
code: imageResizeTestNoZoom,
|
||||||
golden: 'parrot.png',
|
golden: 'parrot.png',
|
||||||
percentage: 0.06,
|
percentage: 0.08,
|
||||||
});
|
});
|
||||||
|
|
||||||
function imageResizeTestGroup(canvas, callback) {
|
function imageResizeTestGroup(canvas, callback) {
|
||||||
getImage(getFixtureName('parrot.png'), false, function(img) {
|
getFixture('parrot.png', false, function(img) {
|
||||||
canvas.setDimensions({
|
canvas.setDimensions({
|
||||||
width: 200,
|
width: 200,
|
||||||
height: 200,
|
height: 200,
|
||||||
|
|
@ -148,11 +87,11 @@
|
||||||
test: 'Image resize with scaled group',
|
test: 'Image resize with scaled group',
|
||||||
code: imageResizeTestGroup,
|
code: imageResizeTestGroup,
|
||||||
golden: 'parrot.png',
|
golden: 'parrot.png',
|
||||||
percentage: 0.06,
|
percentage: 0.08,
|
||||||
});
|
});
|
||||||
|
|
||||||
function blendImageTest2(canvas, callback) {
|
function blendImageTest2(canvas, callback) {
|
||||||
getImage(getFixtureName('parrot.png'), false, function(img) {
|
getFixture('parrot.png', false, function(img) {
|
||||||
var image = new fabric.Image(img);
|
var image = new fabric.Image(img);
|
||||||
var backdropImage = new fabric.Image(img);
|
var backdropImage = new fabric.Image(img);
|
||||||
backdropImage.left = backdropImage.width;
|
backdropImage.left = backdropImage.width;
|
||||||
|
|
@ -181,8 +120,8 @@
|
||||||
});
|
});
|
||||||
|
|
||||||
function blendImageTest(canvas, callback) {
|
function blendImageTest(canvas, callback) {
|
||||||
getImage(getFixtureName('parrot.png'), false, function(img) {
|
getFixture('parrot.png', false, function(img) {
|
||||||
getImage(getFixtureName('very_large_image.jpg'), false, function(backdrop) {
|
getFixture('very_large_image.jpg', false, function(backdrop) {
|
||||||
var image = new fabric.Image(img);
|
var image = new fabric.Image(img);
|
||||||
var backdropImage = new fabric.Image(backdrop);
|
var backdropImage = new fabric.Image(backdrop);
|
||||||
image.filters.push(new fabric.Image.filters.BlendImage({image: backdropImage, alpha: 0.5 }));
|
image.filters.push(new fabric.Image.filters.BlendImage({image: backdropImage, alpha: 0.5 }));
|
||||||
|
|
@ -206,48 +145,5 @@
|
||||||
percentage: 0.06,
|
percentage: 0.06,
|
||||||
});
|
});
|
||||||
|
|
||||||
tests.forEach(function(testObj) {
|
tests.forEach(visualTestLoop(fabricCanvas, QUnit));
|
||||||
var testName = testObj.test;
|
|
||||||
var code = testObj.code;
|
|
||||||
var percentage = testObj.percentage;
|
|
||||||
var golden = testObj.golden;
|
|
||||||
var newModule = testObj.newModule;
|
|
||||||
if (newModule) {
|
|
||||||
QUnit.module(newModule, {
|
|
||||||
beforeEach: beforeEachHandler,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
QUnit.test(testName, function(assert) {
|
|
||||||
var done = assert.async();
|
|
||||||
code(fabricCanvas, function(renderedCanvas) {
|
|
||||||
var width = renderedCanvas.width;
|
|
||||||
var height = renderedCanvas.height;
|
|
||||||
var totalPixels = width * height;
|
|
||||||
var imageDataCanvas = renderedCanvas.getContext('2d').getImageData(0, 0, width, height).data;
|
|
||||||
var canvas = fabric.document.createElement('canvas');
|
|
||||||
canvas.width = width;
|
|
||||||
canvas.height = height;
|
|
||||||
var ctx = canvas.getContext('2d');
|
|
||||||
var output = ctx.getImageData(0, 0, width, height);
|
|
||||||
getImage(getGoldeName(golden), renderedCanvas, function(goldenImage) {
|
|
||||||
ctx.drawImage(goldenImage, 0, 0);
|
|
||||||
visualCallback.addArguments({
|
|
||||||
enabled: true,
|
|
||||||
golden: canvas,
|
|
||||||
fabric: renderedCanvas,
|
|
||||||
diff: output
|
|
||||||
});
|
|
||||||
var imageDataGolden = ctx.getImageData(0, 0, width, height).data;
|
|
||||||
var differentPixels = _pixelMatch(imageDataCanvas, imageDataGolden, output.data, width, height, pixelmatchOptions);
|
|
||||||
var percDiff = differentPixels / totalPixels * 100;
|
|
||||||
var okDiff = totalPixels * percentage;
|
|
||||||
assert.ok(
|
|
||||||
differentPixels < okDiff,
|
|
||||||
testName + ' has too many different pixels ' + differentPixels + '(' + okDiff + ') representing ' + percDiff + '%'
|
|
||||||
);
|
|
||||||
done();
|
|
||||||
});
|
|
||||||
});
|
|
||||||
});
|
|
||||||
});
|
|
||||||
})();
|
})();
|
||||||
|
|
|
||||||
|
|
@ -1,148 +1,78 @@
|
||||||
(function() {
|
(function() {
|
||||||
fabric.enableGLFiltering = false;
|
fabric.enableGLFiltering = false;
|
||||||
fabric.isWebglSupported = false;
|
fabric.isWebglSupported = false;
|
||||||
var _pixelMatch;
|
fabric.Object.prototype.objectCaching = false;
|
||||||
var visualCallback;
|
var visualTestLoop;
|
||||||
var fs;
|
var getAsset;
|
||||||
if (fabric.isLikelyNode) {
|
if (fabric.isLikelyNode) {
|
||||||
fs = global.fs;
|
visualTestLoop = global.visualTestLoop;
|
||||||
_pixelMatch = global.pixelmatch;
|
getAsset = global.getAsset;
|
||||||
visualCallback = global.visualCallback;
|
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
_pixelMatch = pixelmatch;
|
visualTestLoop = window.visualTestLoop;
|
||||||
if (window) {
|
getAsset = window.getAsset;
|
||||||
visualCallback = window.visualCallback;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
var fabricCanvas = this.canvas = new fabric.Canvas(null, {enableRetinaScaling: false, renderOnAddRemove: false});
|
var fabricCanvas = this.canvas = new fabric.Canvas(null, {enableRetinaScaling: false, renderOnAddRemove: false});
|
||||||
var pixelmatchOptions = {
|
|
||||||
includeAA: false,
|
|
||||||
threshold: 0.095
|
|
||||||
};
|
|
||||||
fabric.Object.prototype.objectCaching = false;
|
|
||||||
function getAbsolutePath(path) {
|
|
||||||
var isAbsolute = /^https?:/.test(path);
|
|
||||||
if (isAbsolute) { return path; };
|
|
||||||
var imgEl = fabric.document.createElement('img');
|
|
||||||
imgEl.src = path;
|
|
||||||
var src = imgEl.src;
|
|
||||||
imgEl = null;
|
|
||||||
return src;
|
|
||||||
}
|
|
||||||
|
|
||||||
function getAsset(filename, callback) {
|
function createTestFromSVG(svgName) {
|
||||||
var finalName = '/assets/' + filename + '.svg';
|
var test = function(canvas, callback) {
|
||||||
if (fabric.isLikelyNode) {
|
getAsset(svgName, function(err, string) {
|
||||||
var path = (__dirname + finalName);
|
|
||||||
return fs.readFile(path, { encoding: 'utf8' }, callback);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
var path = getAbsolutePath('/test/visual' + finalName);
|
|
||||||
fabric.util.request(path, {
|
|
||||||
onComplete: function(xhr) {
|
|
||||||
callback(null, xhr.responseText);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function getGolden(filename) {
|
|
||||||
var finalName = '/golden/' + filename + '.png';
|
|
||||||
return fabric.isLikelyNode ? (__dirname + finalName) : getAbsolutePath('/test/visual' + finalName);
|
|
||||||
}
|
|
||||||
|
|
||||||
function getGoldenImage(filename, callback) {
|
|
||||||
var img = fabric.document.createElement('img');
|
|
||||||
img.onload = function() {
|
|
||||||
callback(img);
|
|
||||||
};
|
|
||||||
img.onerror = function(err) {
|
|
||||||
console.log('Image loading errored', err);
|
|
||||||
};
|
|
||||||
img.src = getGolden(filename);
|
|
||||||
}
|
|
||||||
|
|
||||||
// main function
|
|
||||||
function loadAndPrepareCanvasFor(filename, callback) {
|
|
||||||
getGoldenImage(filename, function(img) {
|
|
||||||
var canvas = fabric.document.createElement('canvas');
|
|
||||||
var width = canvas.width = img.width;
|
|
||||||
var height = canvas.height = img.height;
|
|
||||||
fabricCanvas.setDimensions({
|
|
||||||
width: width,
|
|
||||||
height: height
|
|
||||||
});
|
|
||||||
var ctx = canvas.getContext('2d');
|
|
||||||
var outputImageData = ctx.getImageData(0, 0, width, height);
|
|
||||||
ctx.drawImage(img, 0, 0);
|
|
||||||
var goldenImageData = ctx.getImageData(0, 0, width, height);
|
|
||||||
getAsset(filename, function(err, string) {
|
|
||||||
fabric.loadSVGFromString(string, function(objects) {
|
fabric.loadSVGFromString(string, function(objects) {
|
||||||
fabricCanvas.add.apply(fabricCanvas, objects);
|
canvas.add.apply(canvas, objects);
|
||||||
fabricCanvas.renderAll();
|
canvas.renderAll();
|
||||||
visualCallback.addArguments({
|
callback(fabricCanvas.lowerCanvasEl);
|
||||||
enabled: true,
|
|
||||||
golden: canvas,
|
|
||||||
fabric: fabricCanvas.lowerCanvasEl,
|
|
||||||
diff: outputImageData
|
|
||||||
});
|
|
||||||
var fabricImageData = fabricCanvas.contextContainer.getImageData(0, 0, width, height).data;
|
|
||||||
callback(fabricImageData, goldenImageData.data, width, height, outputImageData.data);
|
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
};
|
||||||
|
return {
|
||||||
|
test: 'Svg import test ' + svgName,
|
||||||
|
code: test,
|
||||||
|
golden: svgName + '.png',
|
||||||
|
percentage: 0.06,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
function beforeEachHandler() {
|
||||||
|
fabricCanvas.clipPath = null;
|
||||||
|
fabricCanvas.viewportTransform = [1, 0, 0, 1, 0, 0];
|
||||||
|
fabricCanvas.clear();
|
||||||
|
fabricCanvas.renderAll();
|
||||||
}
|
}
|
||||||
|
|
||||||
QUnit.module('Simple svg import test', {
|
QUnit.module('Simple svg import test', {
|
||||||
beforeEach: function() {
|
beforeEach: beforeEachHandler,
|
||||||
fabricCanvas.clear();
|
|
||||||
fabricCanvas.renderAll();
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
|
|
||||||
[
|
var tests = [
|
||||||
['svg_stroke_1', 0],
|
'svg_stroke_1',
|
||||||
['svg_stroke_2', 0],
|
'svg_stroke_2',
|
||||||
['svg_stroke_3', 0],
|
'svg_stroke_3',
|
||||||
['svg_stroke_4', 8],
|
'svg_stroke_4',
|
||||||
['svg_stroke_5', 4],
|
'svg_stroke_5',
|
||||||
['svg_stroke_6', 83],
|
'svg_stroke_6',
|
||||||
['svg_stroke_7', 0],
|
'svg_stroke_7',
|
||||||
['svg_stroke_8', 0],
|
'svg_stroke_8',
|
||||||
['svg_linear_1', 0],
|
'svg_linear_1',
|
||||||
['svg_linear_2', 0],
|
'svg_linear_2',
|
||||||
['svg_linear_3', 0],
|
'svg_linear_3',
|
||||||
['svg_linear_4', 14],
|
'svg_linear_4',
|
||||||
['svg_linear_5', 8],
|
'svg_linear_5',
|
||||||
['svg_linear_6', 83],
|
'svg_linear_6',
|
||||||
['svg_linear_7', 0],
|
'svg_linear_7',
|
||||||
['svg_linear_8', 0],
|
'svg_linear_8',
|
||||||
['svg_radial_1', 100],
|
'svg_radial_1',
|
||||||
['svg_radial_2', 0],
|
'svg_radial_2',
|
||||||
['svg_radial_3', 0],
|
'svg_radial_3',
|
||||||
['svg_radial_4', 143],
|
'svg_radial_4',
|
||||||
['svg_radial_5', 143],
|
'svg_radial_5',
|
||||||
['svg_radial_6', 8],
|
'svg_radial_6',
|
||||||
['svg_radial_8', 0],
|
'svg_radial_8',
|
||||||
['svg_radial_9', 8],
|
'svg_radial_9',
|
||||||
['svg_radial_10', 12],
|
'svg_radial_10',
|
||||||
['svg_radial_11', 0],
|
'svg_radial_11',
|
||||||
['svg_radial_12', 8],
|
'svg_radial_12',
|
||||||
['svg_radial_13', 4],
|
'svg_radial_13',
|
||||||
].forEach(function(filenameArray) {
|
].map(createTestFromSVG);
|
||||||
var filename = filenameArray[0];
|
|
||||||
// var expectedPixels = filenameArray[1];
|
tests.forEach(visualTestLoop(fabricCanvas, QUnit));
|
||||||
QUnit.test('Import test for file ' + filename, function(assert) {
|
|
||||||
var done = assert.async();
|
|
||||||
loadAndPrepareCanvasFor(filename, function(imageDataCanvas, imageDataGolden, width, height, output) {
|
|
||||||
var totalPixels = width * height;
|
|
||||||
var percentage = 0.01;
|
|
||||||
var differentPixels = _pixelMatch(imageDataCanvas, imageDataGolden, output, width, height, pixelmatchOptions);
|
|
||||||
var percDiff = differentPixels / totalPixels * 100;
|
|
||||||
assert.ok(differentPixels < totalPixels * percentage, 'Image ' + filename + ' has too many different pixels ' + differentPixels + ' representing ' + percDiff + '%');
|
|
||||||
done();
|
|
||||||
});
|
|
||||||
});
|
|
||||||
});
|
|
||||||
})();
|
})();
|
||||||
|
|
|
||||||
|
|
@ -3,6 +3,7 @@
|
||||||
"serve_files": [
|
"serve_files": [
|
||||||
"dist/fabric.js",
|
"dist/fabric.js",
|
||||||
"test/lib/pixelmatch.js",
|
"test/lib/pixelmatch.js",
|
||||||
|
"test/lib/visualTestLoop.js",
|
||||||
"test/lib/visualCallbackQunit.js",
|
"test/lib/visualCallbackQunit.js",
|
||||||
"test/visual/*.js"
|
"test/visual/*.js"
|
||||||
],
|
],
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue