mirror of
https://github.com/Hopiu/fabric.js.git
synced 2026-03-16 22:10:32 +00:00
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:
parent
d6649b2efb
commit
053e419dbb
11 changed files with 114 additions and 17 deletions
|
|
@ -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_ */
|
||||
|
|
|
|||
|
|
@ -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('');
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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(' '),
|
||||
|
||||
|
|
|
|||
|
|
@ -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) {
|
||||
|
|
|
|||
6
test/visual/assets/vector-effect.svg
Normal file
6
test/visual/assets/vector-effect.svg
Normal 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 |
68
test/visual/generic_rendering.js
Normal file
68
test/visual/generic_rendering.js
Normal 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));
|
||||
})();
|
||||
BIN
test/visual/golden/generic1.png
Normal file
BIN
test/visual/golden/generic1.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 377 B |
BIN
test/visual/golden/vector-effect.png
Normal file
BIN
test/visual/golden/vector-effect.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 423 B |
|
|
@ -85,6 +85,7 @@
|
|||
'clippath-6',
|
||||
'clippath-7',
|
||||
'clippath-9',
|
||||
'vector-effect'
|
||||
//'clippath-8',
|
||||
].map(createTestFromSVG);
|
||||
|
||||
|
|
|
|||
Loading…
Reference in a new issue