Hanpan
Hanpan

Reputation: 10251

Scale path from center

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})`);
        

Upvotes: 41

Views: 32124

Answers (3)

Elad Amsalem
Elad Amsalem

Reputation: 1871

You can alter the origin to center:

.scaled-path-svg {
  svg {
    path {
      transform-origin: center;
      transform: scale(1.1);
      transform-box: fill-box;
    }
  }
}

Upvotes: 31

Ethan
Ethan

Reputation: 4995

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.

Upvotes: 3

ᴇʟᴇvᴀтᴇ
ᴇʟᴇvᴀтᴇ

Reputation: 12751

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().

Upvotes: 69

Related Questions