Skip to content

Commit

Permalink
Refinements to strokeUniform property (fabricjs#5527)
Browse files Browse the repository at this point in the history
* 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
  • Loading branch information
asturur committed Feb 17, 2019
1 parent b154cab commit c25a414
Show file tree
Hide file tree
Showing 11 changed files with 113 additions and 16 deletions.
2 changes: 1 addition & 1 deletion HEADER.js
Original file line number Diff line number Diff line change
Expand Up @@ -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_ */
Expand Down
2 changes: 2 additions & 0 deletions src/mixins/object.svg_export.js
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -237,6 +238,7 @@
);
commonPieces = [
styleInfo,
vectorEffect,
noStyle ? '' : this.addPaintOrder(), ' ',
additionalTransform ? 'transform="' + additionalTransform + '" ' : '',
].join('');
Expand Down
40 changes: 28 additions & 12 deletions src/mixins/object_geometry.mixin.js
Original file line number Diff line number Diff line change
Expand Up @@ -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;
dimY = dimensions.y;
}
if (noSkew) {
return this._finalizeDiemensions(dimX * this.scaleX, dimY * this.scaleY);
}
else {
dimX = dimensions.x / 2;
dimY = dimensions.y / 2;
dimX /= 2;
dimY /= 2;
}
var points = [
{
Expand All @@ -624,12 +629,23 @@
points[i] = fabric.util.transformPoint(points[i], transformMatrix);
}
bbox = fabric.util.makeBoundingBoxFromPoints(points);
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: bbox.width + this.strokeWidth, y: bbox.height + this.strokeWidth }
{ x: width + this.strokeWidth, y: height + this.strokeWidth }
:
{ x: bbox.width, y: bbox.height };
{ x: width, y: height };
},

/*
* Calculate object dimensions for controls. include padding and canvas zoom
* private
Expand Down
4 changes: 4 additions & 0 deletions src/parser.js
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,7 @@
opacity: 'opacity',
'clip-path': 'clipPath',
'clip-rule': 'clipRule',
'vector-effect': 'strokeUniform'
},

colorAttributes = {
Expand Down Expand Up @@ -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;
Expand Down
4 changes: 2 additions & 2 deletions src/shapes/object.class.js
Original file line number Diff line number Diff line change
Expand Up @@ -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(' '),

/**
Expand All @@ -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(' '),

Expand Down
2 changes: 1 addition & 1 deletion test/unit/header.js
Original file line number Diff line number Diff line change
Expand Up @@ -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) {
Expand Down
6 changes: 6 additions & 0 deletions test/visual/assets/vector-effect.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
68 changes: 68 additions & 0 deletions test/visual/generic_rendering.js
Original file line number Diff line number Diff line change
@@ -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 added test/visual/golden/generic1.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added test/visual/golden/vector-effect.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
1 change: 1 addition & 0 deletions test/visual/svg_import.js
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,7 @@
'clippath-6',
'clippath-7',
'clippath-9',
'vector-effect'
//'clippath-8',
].map(createTestFromSVG);

Expand Down

0 comments on commit c25a414

Please sign in to comment.