Refinements to strokeUniform property (#5527)

* new Object property strokeUniform allows the stroke width to always stay the same width as object scales

* fix for height

* Update src/shapes/object.class.js

Co-Authored-By: stefanhayden <alt255@gmail.com>

* trying the other function

* different transformed function

* added a visual test

* fixed title

* test svg

* import value from svg

* add svg import test

* more tests
This commit is contained in:
Andrea Bogazzi 2019-02-17 23:08:39 +01:00 committed by GitHub
parent d6649b2efb
commit 053e419dbb
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
11 changed files with 114 additions and 17 deletions

View file

@ -55,7 +55,7 @@ fabric.SHARED_ATTRIBUTES = [
'stroke', 'stroke-dasharray', 'stroke-linecap', 'stroke-dashoffset',
'stroke-linejoin', 'stroke-miterlimit',
'stroke-opacity', 'stroke-width',
'id', 'paint-order',
'id', 'paint-order', 'vector-effect',
'instantiated_by_use', 'clip-path'
];
/* _FROM_SVG_END_ */

View file

@ -213,6 +213,7 @@
styleInfo = noStyle ? '' : 'style="' + this.getSvgStyles() + '" ',
shadowInfo = withShadow ? 'style="' + this.getSvgFilter() + '" ' : '',
clipPath = this.clipPath,
vectorEffect = this.strokeUniform ? 'vector-effect="non-scaling-stroke" ' : '',
absoluteClipPath = this.clipPath && this.clipPath.absolutePositioned,
commonPieces, markup = [], clipPathMarkup,
// insert commons in the markup, style and svgCommons
@ -237,6 +238,7 @@
);
commonPieces = [
styleInfo,
vectorEffect,
noStyle ? '' : this.addPaintOrder(), ' ',
additionalTransform ? 'transform="' + additionalTransform + '" ' : '',
].join('');

View file

@ -588,18 +588,23 @@
if (typeof skewY === 'undefined') {
skewY = this.skewY;
}
var dimensions = this._getNonTransformedDimensions();
if (skewX === 0 && skewY === 0) {
return { x: dimensions.x * this.scaleX, y: dimensions.y * this.scaleY };
}
var dimX, dimY;
var dimensions = this._getNonTransformedDimensions(), dimX, dimY,
noSkew = skewX === 0 && skewY === 0;
if (this.strokeUniform) {
dimX = this.width / 2;
dimY = this.height / 2;
dimX = this.width;
dimY = this.height;
}
else {
dimX = dimensions.x / 2;
dimY = dimensions.y / 2;
dimX = dimensions.x;
dimY = dimensions.y;
}
if (noSkew) {
return this._finalizeDiemensions(dimX * this.scaleX, dimY * this.scaleY);
}
else {
dimX /= 2;
dimY /= 2;
}
var points = [
{
@ -624,12 +629,23 @@
points[i] = fabric.util.transformPoint(points[i], transformMatrix);
}
bbox = fabric.util.makeBoundingBoxFromPoints(points);
return this.strokeUniform ?
{ x: bbox.width + this.strokeWidth, y: bbox.height + this.strokeWidth }
:
{ x: bbox.width, y: bbox.height };
return this._finalizeDiemensions(bbox.width, bbox.height);
},
/*
* Calculate object bounding boxdimensions from its properties scale, skew.
* @param Number width width of the bbox
* @param Number height height of the bbox
* @private
* @return {Object} .x finalized width dimension
* @return {Object} .y finalized height dimension
*/
_finalizeDiemensions: function(width, height) {
return this.strokeUniform ?
{ x: width + this.strokeWidth, y: height + this.strokeWidth }
:
{ x: width, y: height };
},
/*
* Calculate object dimensions for controls. include padding and canvas zoom
* private

View file

@ -49,6 +49,7 @@
opacity: 'opacity',
'clip-path': 'clipPath',
'clip-rule': 'clipRule',
'vector-effect': 'strokeUniform'
},
colorAttributes = {
@ -80,6 +81,9 @@
if ((attr === 'fill' || attr === 'stroke') && value === 'none') {
value = '';
}
else if (attr === 'vector-effect') {
value = value === 'non-scaling-stroke';
}
else if (attr === 'strokeDashArray') {
if (value === 'none') {
value = null;

View file

@ -607,7 +607,7 @@
'top left width height scaleX scaleY flipX flipY originX originY transformMatrix ' +
'stroke strokeWidth strokeDashArray strokeLineCap strokeDashOffset strokeLineJoin strokeMiterLimit ' +
'angle opacity fill globalCompositeOperation shadow clipTo visible backgroundColor ' +
'skewX skewY fillRule paintFirst clipPath'
'skewX skewY fillRule paintFirst clipPath strokeUniform'
).split(' '),
/**
@ -618,7 +618,7 @@
* @type Array
*/
cacheProperties: (
'fill stroke strokeWidth strokeDashArray width height paintFirst' +
'fill stroke strokeWidth strokeDashArray width height paintFirst strokeUniform' +
' strokeLineCap strokeDashOffset strokeLineJoin strokeMiterLimit backgroundColor clipPath'
).split(' '),

View file

@ -6,7 +6,7 @@
assert.ok(typeof fabric.window !== 'undefined', 'window is set');
assert.ok(typeof fabric.isTouchSupported !== 'undefined', 'isTouchSupported is set');
assert.ok(typeof fabric.isLikelyNode !== 'undefined', 'isLikelyNode is set');
assert.equal(fabric.SHARED_ATTRIBUTES.length, 18, 'SHARED_ATTRIBUTES is set');
assert.equal(fabric.SHARED_ATTRIBUTES.length, 19, 'SHARED_ATTRIBUTES is set');
});
QUnit.test('initFilterBackend', function(assert) {

View file

@ -0,0 +1,6 @@
<?xml version="1.0" standalone="no" ?>
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1" width="150" height="150" xml:space="preserve">
<rect x="1" y="1" width="20" height="20" transform="matrix(4 0 0 1.5 0 0)" stroke-width="3" vector-effect="non-scaling-stroke" fill="none" stroke="red" />
<rect x="4" y="4" width="20" height="20" transform="matrix(4 0 0 1.5 0 0)" stroke-width="3" fill="none" stroke="blue" />
</svg>

After

Width:  |  Height:  |  Size: 569 B

View file

@ -0,0 +1,68 @@
(function() {
if (fabric.isLikelyNode) {
if (process.env.launcher === 'Firefox') {
fabric.browserShadowBlurConstant = 0.9;
}
if (process.env.launcher === 'Node') {
fabric.browserShadowBlurConstant = 1;
}
if (process.env.launcher === 'Chrome') {
fabric.browserShadowBlurConstant = 1.5;
}
if (process.env.launcher === 'Edge') {
fabric.browserShadowBlurConstant = 1.75;
}
}
else {
if (navigator.userAgent.indexOf('Firefox') !== -1) {
fabric.browserShadowBlurConstant = 0.9;
}
if (navigator.userAgent.indexOf('Chrome') !== -1) {
fabric.browserShadowBlurConstant = 1.5;
}
if (navigator.userAgent.indexOf('Edge') !== -1) {
fabric.browserShadowBlurConstant = 1.75;
}
}
fabric.enableGLFiltering = false;
fabric.isWebglSupported = false;
fabric.Object.prototype.objectCaching = true;
var visualTestLoop;
if (fabric.isLikelyNode) {
visualTestLoop = global.visualTestLoop;
}
else {
visualTestLoop = window.visualTestLoop;
}
var fabricCanvas = this.canvas = new fabric.Canvas(null, {
enableRetinaScaling: false, renderOnAddRemove: false, width: 200, height: 200,
});
var tests = [];
function generic1(canvas, callback) {
canvas.setDimensions({ width: 150, height: 60 });
var rect = new fabric.Rect({
width: 20, height: 40, strokeWidth: 2, scaleX: 6, scaleY: 0.5, strokeUniform: true,
fill: '', stroke: 'red'
});
var rect2 = new fabric.Rect({
width: 60, height: 60, top: 4, left: 4, strokeWidth: 2, scaleX: 2,
scaleY: 0.5, strokeUniform: false, fill: '', stroke: 'blue',
});
canvas.add(rect);
canvas.add(rect2);
canvas.renderAll();
callback(canvas.lowerCanvasEl);
}
tests.push({
test: 'Rect with strokeUniform: true',
code: generic1,
golden: 'generic1.png',
newModule: 'Generic rendering',
percentage: 0.09,
});
tests.forEach(visualTestLoop(fabricCanvas, QUnit));
})();

Binary file not shown.

After

Width:  |  Height:  |  Size: 377 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 423 B

View file

@ -85,6 +85,7 @@
'clippath-6',
'clippath-7',
'clippath-9',
'vector-effect'
//'clippath-8',
].map(createTestFromSVG);