From 5928cf4b2876005bc1fd8d98e3b782a5dbe9129b Mon Sep 17 00:00:00 2001 From: Dany Date: Wed, 7 Oct 2026 08:07:51 -0700 Subject: [PATCH] fix SVG preserveAspectRatio none handling --- src/shape/svg/svg_import.js | 28 +++++++++++++++++++++------- test/unit/svg/svg_import.js | 37 +++++++++++++++++++++++++++++++++++++ 2 files changed, 58 insertions(+), 7 deletions(-) diff --git a/src/shape/svg/svg_import.js b/src/shape/svg/svg_import.js index 5f363c8b54..b0ed21c138 100644 --- a/src/shape/svg/svg_import.js +++ b/src/shape/svg/svg_import.js @@ -699,12 +699,26 @@ export function SVGImportAddon(p5, fn, lifecycles) { ? this.num(node, "height") : (referenced.height?.baseVal?.value || vb.height); - const scale = Math.min(w / vb.width, h / vb.height); // default: xMidYMid meet - this.tStack.current.translateSelf( - (w - vb.width * scale) / 2 - vb.x * scale, - (h - vb.height * scale) / 2 - vb.y * scale - ); - this.tStack.current.scaleSelf(scale, scale); + const preserveAspectRatio = referenced.getAttribute("preserveAspectRatio"); + + if (preserveAspectRatio?.trim() === "none") { + const scaleX = w / vb.width; + const scaleY = h / vb.height; + + this.tStack.current.translateSelf( + -vb.x * scaleX, + -vb.y * scaleY + ); + this.tStack.current.scaleSelf(scaleX, scaleY); + } else { + const scale = Math.min(w / vb.width, h / vb.height); // default: xMidYMid meet + + this.tStack.current.translateSelf( + (w - vb.width * scale) / 2 - vb.x * scale, + (h - vb.height * scale) / 2 - vb.y * scale + ); + this.tStack.current.scaleSelf(scale, scale); + } } this.visit(referenced); }); @@ -1623,4 +1637,4 @@ export function SVGImportAddon(p5, fn, lifecycles) { if (typeof p5 !== 'undefined') { p5.registerAddon(SVGImportAddon); -} \ No newline at end of file +} diff --git a/test/unit/svg/svg_import.js b/test/unit/svg/svg_import.js index a0545b9e5e..d4acf1d594 100644 --- a/test/unit/svg/svg_import.js +++ b/test/unit/svg/svg_import.js @@ -1134,6 +1134,43 @@ suite(' and elements', function () { }); }); + test('use respects preserveAspectRatio=none', function () { + const record = createSVG(` + + + + + + + + + `); + const scope = firstChild(record); + const node = scope.children[0]; + assert.closeTo(node.state.transform.a, 2, 0.001); + assert.closeTo(node.state.transform.d, 1, 0.001); + }); + + test('use with preserveAspectRatio=none accounts for viewBox origin', function () { + const record = createSVG(` + + + + + + + + + `); + const scope = firstChild(record); + const node = scope.children[0]; + + assert.closeTo(node.state.transform.a, 2, 0.001); + assert.closeTo(node.state.transform.d, 1, 0.001); + assert.closeTo(node.state.transform.e, -20, 0.001); + assert.closeTo(node.state.transform.f, -20, 0.001); + }); + test('handles missing references gracefully', function () { const record = createSVG(`