Scale Path from Center

Scale path from center

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

How to transform: scale() from the center of the path?

You have to calculate the Scale centerpoint (actually a translate) for each of the 6 <path> shapes.

Use a standard JavaScript Web Component <svg-hexagon> to create all dynamically.

I leave the animations to you:

customElements.define("svg-hexagon", class extends HTMLElement {
connectedCallback() {
this.innerHTML = `<svg viewBox="0 0 1500 1500">` +
`<style>path{stroke:red;stroke-width:15;fill:lightgreen}path:hover{fill:gold}</style>` +
`<g transform="scale(0.8) translate(200 200)"></g></svg>`;
let paths = this.querySelector("g");
let xPos = 360;
for (let i = 0; i < 6; i++) {
let path = document.createElementNS("http://www.w3.org/2000/svg", "path");
let pathlocation = `rotate(${i*60} 750 750)`;
path.setAttribute("transform", pathlocation);
path.setAttribute("d", `m${xPos} 935 0-369 0 0-301-173 0 0 0 716h0l301-173`);
paths.append(path);
path.onmouseenter = (e) => {
let {left,top,x,y,width,height } = path.getBBox();
let scale = 1.5;
let cx = -(x + (width / 2)) * (scale - 1);
let cy = -(y + (height / 2)) * (scale - 1);
path.setAttribute("transform",
`${pathlocation} translate(${cx} ${cy}) scale(${scale})`);
paths.append(path); // put path on top, there is no z-index in SVG
}
path.onmouseleave = (e) => {
if(!e.ctrlKey) path.setAttribute("transform", pathlocation);
}
}
}
})
svg-hexagon {
width: 180px;
display: inline-block;
background: rebeccapurple
}
<svg-hexagon></svg-hexagon>
<svg-hexagon></svg-hexagon>
<svg-hexagon></svg-hexagon>

SVG Scale group from his center

You appear to have got your centre wrong. You are scaling around the wrong centre point.

You are dividing canvasBBox width and height by two, but you are not taking into account the x and y values of the bbox.

The centre of the #Canvas element is at

var cx = canvasBbox.x + canvasBbox.width/2;
var cy = canvasBbox.y + canvasBbox.height/2;

If you update the calculation with these values, you get your expected result.

var rectangle = document.querySelector("#Rectangle")var rectangleScaled = document.querySelector("#RectangleScaled")
var canvasBbox = document.querySelector("#Canvas").getBBox()
var cx = canvasBbox.x + canvasBbox.width/2;var cy = canvasBbox.y + canvasBbox.height/2;
var x = -cx * (1.4 - 1)var y = -cy * (1.4 - 1)
rectangleScaled.style.transform = "translate("+x+"px, "+y+"px) scale(1.4)"
<svg width="411" height="731" viewBox="0 0 411 731" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">  <g id="Canvas" transform="translate(721 384)">    <clipPath id="clip-0" clip-rule="evenodd">      <path d="M -721 -384L -310 -384L -310 347L -721 347L -721 -384Z" fill="#FFFFFF"/>    </clipPath>    <g id="Google Pixel" clip-path="url(#clip-0)">      <path d="M -721 -384L -310 -384L -310 347L -721 347L -721 -384Z" fill="#FFFFFF"/>
<g id="RectangleScaled"> <use xlink:href="#path1_fill" transform="translate(-614 -152)" fill="red"/> </g> <g id="Rectangle"> <use xlink:href="#path0_fill" transform="translate(-614 -152)" fill="#C4C4C4"/> </g> </g> </g> <defs> <path id="path0_fill" d="M 0 0L 196 0L 196 266L 0 266L 0 0Z"/> <path id="path1_fill" d="M 0 0L 196 0L 196 266L 0 266L 0 0Z"/> </defs></svg>

Svg scale path at a center point (pulsating)

There is a simple solution, that is cross-browser.

Just give each of your sunbeams its own absolute transform-origin.

    .wrapper {      width: 100px;      text-align: center;    }    .icon-sun-beam {      animation-name: scale;      animation-duration: 3s;      animation-iteration-count: infinite;      animation-timing-function: linear;      animation-fill-mode: both;      animation-direction: alternate;          }        .icon-sun-beam:nth-child(even) {      animation-delay: 4.5s, 4.5s;    }        .icon-sun {      animation-name: rotate;      animation-iteration-count: infinite;      animation-duration: 18s;      animation-timing-function: linear;      transform-origin: 50px 50px;    }        svg {      shape-rendering: geometricPrecision;    }        @keyframes rotate {      0% {        transform: rotate(0);      }      100% {        transform: rotate(360deg);      }    }        @keyframes scale {      0% {        transform: scale(0.85, 0.85);      }      100% {        transform: scale(1.35, 1.35);      }    }
<div class="wrapper">              <svg version="1.1" viewBox="20 20 60 60" >              <g class="icon-sun">                  <path class="icon-sun-beam" style="transform-origin: 70.0px 50.0px;"                        d="M72.03,51.999                         h-3.998                         c-1.105,0-2-0.896-2-1.999                         s0.895-2,2-2h3.998                        c1.104,0,2,0.896,2,2                        S73.136,51.999,72.03,51.999z"/>                  <path class="icon-sun-beam" style="transform-origin: 64.2px 35.9px;"                        d="M64.175,38.688c-0.781,0.781-2.049,0.781-2.828,0c-0.781-0.781-0.781-2.047,0-2.828l2.828-2.828c0.779-0.781,2.047-0.781,2.828,0c0.779,0.781,0.779,2.047,0,2.828L64.175,38.688z"/>                  <path class="icon-sun-beam" style="transform-origin: 50.0px 30.0px;"                        d="M50.034,34.002c-1.105,0-2-0.896-2-2v-3.999c0-1.104,0.895-2,2-2c1.104,0,2,0.896,2,2v3.999C52.034,33.106,51.136,34.002,50.034,34.002z"/>                  <path class="icon-sun-beam" style="transform-origin: 35.9px 35.9px;"                        d="M35.893,38.688l-2.827-2.828c-0.781-0.781-0.781-2.047,0-2.828c0.78-0.781,2.047-0.781,2.827,0l2.827,2.828c0.781,0.781,0.781,2.047,0,2.828C37.94,39.469,36.674,39.469,35.893,38.688z"/>                  <path class="icon-sun-beam" style="transform-origin: 30.0px 50.0px;"                        d="M34.034,50c0,1.104-0.896,1.999-2,1.999h-4c-1.104,0-1.998-0.896-1.998-1.999s0.896-2,1.998-2h4C33.14,48,34.034,48.896,34.034,50z"/>                  <path class="icon-sun-beam" style="transform-origin: 35.9px 64.1px;"                        d="M35.893,61.312c0.781-0.78,2.048-0.78,2.827,0c0.781,0.78,0.781,2.047,0,2.828l-2.827,2.827c-0.78,0.781-2.047,0.781-2.827,0c-0.781-0.78-0.781-2.047,0-2.827L35.893,61.312z"/>                  <path class="icon-sun-beam" style="transform-origin: 50.0px 70.0px;"                        d="M50.034,65.998c1.104,0,2,0.895,2,1.999v4c0,1.104-0.896,2-2,2c-1.105,0-2-0.896-2-2v-4C48.034,66.893,48.929,65.998,50.034,65.998z"/>                  <path class="icon-sun-beam" style="transform-origin: 64.2px 64.1px;"                        d="M64.175,61.312l2.828,2.828c0.779,0.78,0.779,2.047,0,2.827c-0.781,0.781-2.049,0.781-2.828,0l-2.828-2.827c-0.781-0.781-0.781-2.048,0-2.828C62.126,60.531,63.392,60.531,64.175,61.312z"/>                  <circle class="icon-sun-outline"                          cx="50.034"                          cy="50"                          r="11.999"/>                  <circle class="icon-sun-fill"                          fill="#FFFFFF"                          cx="50.034"                          cy="50"                          r="7.999"/>                </g>          </svg>    </div>

SVG - scale path from center repetitively (pulsating)

The scale() transformation (as all others do similarly) basically just multiplies all coordinate values with the respective scaling factor. As a result, if your object is not centered at the origin (0,0), it seems to move away from the center.

So the easy solution is, to have your object with its center at the origin, apply the transformation and the move it to wherever you want to have it.

For the sake of laziness I just moved your path element using a transform="translate(-100 -100)". The same effect could be achieved by modifying the coordinates themselves.

<!-- the other code -->
<path d="..." opacity="0.5" fill="url(#SVGID_4_)"
stroke="url(#SVGID_4_)" stroke-width="0.5" stroke-miterlimit="10"
transform="translate(-100 -100)"/>
<!-- more other code -->

Example Fiddle

Scale svg from center with css animation

Use transform-origin and transform-box and avoid all that translate guessing you're doing.

div { width: 100px; height: 100px; background: rgba(0,0,0,0.2)}            #circle {          transform: scale(1);          transform-box: fill-box;          transform-origin: center;          animation: circle .5s linear 1.3s forwards;        }            @keyframes circle {          to {            transform: scale(4.1);          }        }
<div>      <svg width="100px" height="100px" viewBox="0 0 100 100" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">          <g id="circle" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd">              <circle id="Oval" fill="#2A2C32" cx="50" cy="50" r="11.5"></circle>          </g>      </svg>    </div>

SVG scaling from center point

You've made it hard for yourself by using clip paths. Your problem is that the clip Paths have absolute coordinates. When you scale the <a> element up, you can't tell anything has happened because the clip path has stayed the same size.

You need to scale the clip path up. Which you can only do with Javascript. See below.

var item = document.getElementById("item1");
item.addEventListener("mouseover", function(evt) { document.querySelector("#c1 path").setAttribute("transform", "translate(155,40) scale(1.5) translate(-155,-40)");});
item.addEventListener("mouseout", function(evt) { document.querySelector("#c1 path").removeAttribute("transform");});
a {  display: block;  width: 1500px;  height: 850px;  transition: all .2s;  font-size: 0;  position: absolute;  background: black;}
a:hover { background: gray;}
svg { display: block; height: 0;}
div#navPanel { margin-top: 50px; margin-left: 10vw;}
<head>  <svg>    <defs>      <clipPath id="c1">        <path        d="        M 10, 0        L 200, 80        L 300, 60        Z        " />      </clipPath>    </defs>  </svg></head><body>  <div id="navPanel">    <a id="item1" href="#1" class="clipPath1" style="clip-path: url(#c1)">Click me...</a>  </div></body>

How to make svg path element scale up and down from the elements unknown center point?

  1. you actually need to calculate cx and cy in selected_colour at the moment you're just using strings
  2. you'd need to convert from the cx and cy strings to the values of those variables
  3. there's no such attribute as translate and even if there were the translates would overwrite.
  4. you need to set all the transforms in a single step

 function unselected_colour(evt) {
// get the element that triggered the browser event
let target = evt.target;
// modify the element
target.setAttribute('transform', 'scale(1)')

}
function selected_colour(evt) {
// get the element that triggered the browser event
let target = evt.target;
// modify the element
let rect = target.getBBox();

let cx = rect.x + rect.width / 2;
let cy = rect.y + rect.height / 2;
target.setAttribute('transform', `translate(${cx}, ${cy}) scale(1.25) translate(${-cx},${-cy})`)

}

// find the SVG rectangle in the DOM
let mileEndRoad_obj = document.getElementById('mile_end_road');
let bandcroftRoad_obj = document.getElementById('bandcroft_road');

let godwardSquare_obj = document.getElementById('godward_sqaure');
var godWard_Rect = godwardSquare_obj.getBBox();
godwardSquare_obj.setAttribute('x', godWard_Rect.x);
godwardSquare_obj.setAttribute('y', godWard_Rect.y);
godwardSquare_obj.setAttribute('width', godWard_Rect.width);
godwardSquare_obj.setAttribute('height', godWard_Rect.height);
godwardSquare_obj.setAttribute('cx', (godWard_Rect.x+0.5*godWard_Rect.width));
godwardSquare_obj.setAttribute('cy', (godWard_Rect.y+0.5*godWard_Rect.height));


let compSci_obj = document.getElementById('computer_science');

let itl_obj = document.getElementById('itl');
let engineering_obj = document.getElementById('engineering');
let peoplePalace_obj = document.getElementById('people_palace');

// pass the above functions as callbacks, to be triggered by mouse events
godwardSquare_obj.addEventListener('mouseover', selected_colour, false);
godwardSquare_obj.addEventListener('mouseout', unselected_colour, false);

compSci_obj.addEventListener('mouseover', selected_colour, false);
compSci_obj.addEventListener('mouseout', unselected_colour, false);

itl_obj.addEventListener('mouseover', selected_colour, false);
itl_obj.addEventListener('mouseout', unselected_colour, false);

engineering_obj.addEventListener('mouseover', selected_colour, false);
engineering_obj.addEventListener('mouseout', unselected_colour, false);

peoplePalace_obj.addEventListener('mouseover', selected_colour, false);
peoplePalace_obj.addEventListener('mouseout', unselected_colour, false);
  <svg width="1640" height="480" xmlns="http://www.w3.org/2000/svg" xmlns:svg="http://www.w3.org/2000/svg">
<!-- Created with SVG-edit - https://github.com/SVG-Edit/svgedit-->
<g class="layer">
<title>map</title>
<path d="m38,86.66667l0,94l64.66666,0l0.00001,-28l8.66666,0l0,27.33333l35.33334,0l-11.33334,-20l-12.66666,0l-0.00001,-8c8,0 12.66667,0 12.66667,0c0,0 -0.66667,-65.33333 0,-65.33333c0.66667,0 -89.33333,0 -97.33333,0z"
fill="rgb(94,43,126)" id="computer_science" stroke="#000000" stroke-width="5"/>

<rect fill="#10a3a3" height="447.44527" id="bandcroft_road" stroke="#10a3a3" stroke-width="5" width="35.76642" x="308.90512" y="-24.52553"/>
<rect fill="#10a3a3" height="54.74453" id="mile_end_road" stroke="#10a3a3" stroke-width="5" width="647.44528" x="-1.31387" y="425.10952"/>

<path d="m239.41174,257.50001l-133.52938,-0.14706l-0.00001,-69.85294l50.7353,-0.00001l-16.17647,-31.61765l58.82353,0l0,30.14706l39.70588,0l0.44115,71.4706z"
fill="#1bd1a6" id="godward_sqaure" stroke="#1bd1a6" stroke-width="5"/>

<rect fill="rgb(94,43,126)" height="100.5" id="itl" stroke="#000000" stroke-width="5" width="65" x="37" y="192"/>

<path d="m174.99947,274.5c-0.33149,41.16667 0.33149,82.83333 0,124l290.39161,0l0,-11.5l69.138332,0l0,-37l-68.641082,0l0,-142.5l-101.93541,0l0,167.5l-73.09515,0l0,-101l-115.8583,0.5z"
fill="rgb(94,43,126)" id="engineering" stroke="#000000" stroke-width="5"/>

<path d="m534.99996,206.029419l70.147082,-0.147072c0,0 0.441155,35.441191 -0.294139,34.705896c-0.735294,-0.735294 33.088235,0.000001 32.64708,-0.147072c-0.441155,-0.147073 0.441156,39.852955 0,39.705882c-0.441155,-0.147073 -18.676491,0.147074 -19.117647,0c-0.441156,-0.147073 0.441155,116.323546 0,116.176471c-0.441155,-0.147076 -82.647081,0.882369 -83.088235,0.735294c-0.441154,-0.147076 -0.294141,-191.764693 -0.294141,-191.029399z"
fill="rgb(94,43,126)" id="people_palace" stroke="#000000" stroke-width="5"/>
</g>
</svg>


Related Topics



Leave a reply



Submit