Stretching svg costumes keeps proportion

When stretching an svg costume, it is not possible to stretch x- and y-direction independently. Instead both coordinates will be stretched with the same factor (the minimum of both factors, as it seems).

This command does not give the expected result:
switch to costume (stretch "svg costume" x: 100 y: 50 %)
Instead it gives the same result as:
switch to costume (stretch "svg costume" x: 50 y: 50 %)

Hi, welcome to the forum!

Right, those costume manipulations work only on bitmaps. Also today we got a report that converting an svg to bitmap in the Paint Editor doesn't work, so maybe this is the same problem, and it tried to convert and failed.

Anyway, thanks for reporting this, and we'll look into it!

Hi and thanks for the welcome. :slight_smile:

That other report about converting from SVG to bitmap is also from me. It turned out that this is a separate issue.

I have done some further tests and found a workaround:

To achieve the expected result for

switch to costume (stretch "svg costume" x: 100 y: 50 %)

one can do the following:

// first convert costume to bitmap without stretching
switch to costume (stretch "svg costume" x: 100 y: 100 %)
// then stretch the converted costume
switch to costume (stretch "current" x: 100 y: 50 %)

The same can be done in the JavaScript code in Costume.prototype.stretched. It seems that

ctx.scale(xRatio, yRatio);
ctx.drawImage(this.contents, 0, 0);

is not scaled correctly if this.contents has an inline SVG as its src (at least in Firefox). Drawing the SVG to a temporary canvas solves the problem:

ctx.scale(xRatio, yRatio);
if (this instanceof SVG_Costume) {
    var canvasTemp = newCanvas(new Point(this.width(), this.height())),
        ctxTemp = canvasTemp.getContext('2d');
    ctxTemp.drawImage(this.contents, 0, 0);
    ctx.drawImage(canvasTemp, 0, 0);
} else {
    ctx.drawImage(this.contents, 0, 0);
}

Can you take over?

not sure what this is about. Stretching SVG costumes with different x- and y proportions totally works for me. Can you share a project where this doesn't work? Thanks!

Ok, it seems I have run into a browser problem: Firefox Quantum 69.0 has the problem, both in 32-bit and 64-bit versions, both on Windows and Linux. In Chromium and Edge everything works as expected. Where can I upload a project.xml?

Aha, so it's a browser specific issue. You can simply share or publish your project and paste the url here. Thanks!

But yeah, I can see that Firefox doesn't do it right. Sigh. Browsers. I wish they'd suck less.

I was not aware that this was just a problem of Firefox before you asked. But I could have guessed it from the analysis ...

So here is a small project showing the problem. You have to go to the code and start the command blocks. (see also the code comments)

So I set off to create a minimal example (HTML/SVG/JavaScript) to create a bug report to Mozilla/Firefox. Then I stumbled about this line in sketch.js in method VectorPaintEditorMorph.prototype.getSVG:

....
svg.attributes.preserveAspectRatio = 'xMinYMin meet';
....

The MDN documentation for preserveAspectRatio says that for all alignment specs in preserveAspectRatio different from "none" uniform scaling is forced. So I am not sure now which browsers are doing it right or wrong.

Anyway, changing the above code line to

svg.attributes.preserveAspectRatio = 'none meet';

seems to do the expected thing on all browsers (up to now tested in Firefox 69.0 and Chromium). You can see that in my snap project from above, when you go to the code: I have duplicated the existing costume 'ring' to a costume 'no uniform scaling' and just recreated its SVG code in a local modification of snap. Depending on which SVG costume you choose you get a circular or elliptical ring when only stretching in one direction (in Firefox!).

Wow! That's good find! But this only works for costumes that are edited in Snap's own vector editor, right? Because I've also noticed the "wrong" (not sure anymore if it really is) behavior in imported SVGs. Anyway, this is a great catch, thank you!

Thanks for the roses. Yeah, as far as I can see VectorPaintEditorMorph.prototype.getSVG only affects SVG costumes drawn in Snap. So a solution automatically allowing non-uniform scaling on all costumes in all browsers wouId still have to go via a temporary bitmap since the SVG attributes of an external SVG can currently not be controlled by Snap. It still seems weird to me that SVG-code can prevent a canvas to draw it non-uniformly scaled, but this is what MDN documentation seems to tell - and it could also be seen as a feature. From this perspective the solution should only set the attribute preserveAspectRatio of costumes drawn in Snap accordingly. And allowing non-uniform scaling on the level of programming in Snap is also easy: either generate a bitmap costume or do two stretch commands (as in my example project), so we would not be restricted with this solution. You decide!