Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Scale path from center

Tags:

html

svg

I have the following SVG graphic:

<svg version="1.1" id="diagram" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px" width="375px" height="150px">
    <path d="M45,11.5H33.333c0.735-1.159,1.167-2.528,1.167-4C34.5,3.364,31.136,0,27,0s-7.5,3.364-7.5,7.5c0,1.472,0.432,2.841,1.167,4H9l-9,32h54L45,11.5z M22.5,7.5C22.5,5.019,24.519,3,27,3s4.5,2.019,4.5,4.5c0,1.752-1.017,3.257-2.481,4h-4.037 C23.517,10.757,22.5,9.252,22.5,7.5z" id="control"/>
</svg>

I want to programmatically change the scale of this object, but I want it to scale from the center point.

I've tried wrapping it around a <g> tag, like so

<g transform="translate(0,0)">
<path x="0" y="0" id="control" transform="scale(2)">...</path>
</g>

But this doesn't seem to work. It seems that scaling a path requires manipulation of the path's matrix, which seems horrifically difficult. Annoyingly, it's easy to scale using additive="sum" property but in this instance, I am not using a transform animation.

Can anyone help me out?

Edit: Managed to get this working nicely, for anyone who is stuck on the same thing, here is a nice way of doing it programmatically:

var elem = document.getElementById("control");
var bBox = elem.getBBox();
var scaleX = 2;
var scaleY = 2;
$(elem).attr("transform", `scale(${scaleX}, ${scaleY}) translate(${-bBox.width/2},${-bBox.height/2})`);
        
like image 543
Hanpan Avatar asked Jul 26 '12 14:07

Hanpan


3 Answers

If you know the coordinates of the center point, then you can combine a translate and scale in one transformation. The translation is calculated as: (1 - scale) * currentPosition.

If the center is (10, 20) and you are scaling by 3 then translate by (1 - 3)*10, (1 - 3)*20 = (-20, -40):

<g transform="translate(-20, -40) scale(3)">
    <path d="M45,11.5H33.333c0.735-1.159,1.167-2.528,1.167-4C34.5,3.364,31.136,0,27,0s-7.5,3.364-7.5,7.5c0,1.472,0.432,2.841,1.167,4H9l-9,32h54L45,11.5z M22.5,7.5C22.5,5.019,24.519,3,27,3s4.5,2.019,4.5,4.5c0,1.752-1.017,3.257-2.481,4h-4.037 C23.517,10.757,22.5,9.252,22.5,7.5z" id="control"/>
</g>

The transformations are applied in reverse order from the one they are declared, so in the example, above, the scale is performed first and then the translate. Scaling affects the coordinates so the translation here is in scaled coordinates.

You can calculate the center point programmatically using element.getBBox().

like image 164
ᴇʟᴇvᴀтᴇ Avatar answered Nov 11 '22 16:11

ᴇʟᴇvᴀтᴇ


You can alter the origin to center:

.scaled-path-svg {
  svg {
    path {
      transform-origin: center;
      transform: scale(1.1);
    }
  }
}
like image 33
Elad Amsalem Avatar answered Nov 11 '22 17:11

Elad Amsalem


The answer provided by aetheria earlier is great. There is another thing to take care of as well -- stroke-width, so that the outline stays of the same width while the object scales. Usage:

stroke-width: (1/scaling-factor)

So, if your scaling is by say 2, then:

stroke-width: (0.5)

NOTE: You shouldn't missout the transform: translate(...) scale(2) as mentioned by aetheria.

like image 2
Ethan Avatar answered Nov 11 '22 15:11

Ethan